even though the ThemeChange object changes everytime the App component gets rerendered... I still don't know why it is not causing useEffect to execute whenever I either change the number or click on toggleTheme button... I am severely confused
import React,{useState, useMemo, useEffect} from 'react'
import './App.css';
function App() {
const [dark, setDark] = useState(false),
[number, setNumber] = useState(0)
const SlowFunction = num => {
for(let i=1; i<=10000; i) {}
return num*2
}
const TwiceNo = useMemo(() => {
return SlowFunction(number)
}, [number])
const ThemeChange = {
backgroundColor : dark ? 'black' : 'white',
color : dark ? 'white' : 'black'
}
useEffect(() => {
console.log('theme was changed!')
}, [ThemeChange])
return (
<div className="App">
<input type="number" onChange = {e => {setNumber(parseInt(e.target.value), console.log(e))}} />
<button onClick={() => setDark(e => !e)}>toggle theme</button>
<div style={ThemeChange}>{TwiceNo}</div>
</div>
);
}
export default App;
CodePudding user response:
Javascript objects will not be the same when your component is rerender ( google search more about that) -> Your effect will run every time component rerender because the deps is different. Try to specify the deps.
Like this
useEffect(() => { console.log(Date.now(), "theme was changed!"); }, [ThemeChange.backgroundColor, ThemeChange.color]);
or even better version use this useEffect(() => { console.log(Date.now(), "theme was changed!"); }, [dark]);
CodePudding user response:
Objects are tracked by reference, so there is 2 ways to achieve your goal:
- Set a object with a new reference like using spread operator, or Object.assign
- Check for object equality using JSON.stringify (not recommended for deep objects though)
So try
useEffect(() => {
console.log('theme was changed!')
}, [JSON.stringify(ThemeChange)])