useEffect not working when dependency value changed
Solution 1
Your both dispatch are called after first render so even before your second render value is 0 so your second useEffect won't be able detect change as there is no change.
Let's see what is happening in your render method
First Render:
a = 0
first useEffect: dispatch({ a : 1 })
second useEffect: dispatch({ a : 0 })
so now in your redux store a is 0.
Second Render
a = 0
first useEffect: doesn't run as there is no dependency
second useEffect: doesn't run as a hans't changed.
Solution 2
PLEASE, stop using
useSelector(state => state.mainReducer);
it doesn't make any sense
there should be a simple state transformation (subselection)
const a = useSelector(state => state.a)
taken directly from redux docs:
const counter = useSelector(state => state.counter)
update
you can see effect (from store change) with slightly changed component
function MyComponent(props) {
const a = useSelector(state => state.a);
const dispatch = useDispatch();
console.log('render: ', a);
useEffect(() => {
console.log('use effect: ', a);
dispatch({ type: 'A', payload: a });
}, [a])
useEffect(() => {
console.log('did mount: ', a);
dispatch({ type: 'A', payload: 1 })
}, []);
return (<View style={styles.container}>
<Text style={styles.text}>{a}</Text>
</View>);
};
It should result in log:
render: 0
// initial stateuse effect: 0
// first effect run- // dispatch
0
... processed in store by reducer but results in the same state ...
// ... and in our rendering process we still working on an 'old'a
readed from state on the beginning of render did mount: 0
// 'old'a
// dispatch1
... changed state in redux store.... rendered text
0
...
...//
useSelector
forces rerendering - change detectedrender: 1
// latest dispatched value, processed by reducers into new state, rereaded by selectoruse effect: 1
//useEffect
works AS EXPECTED as an effect ofa
change- .... rendered text
1
...
...
- no more rerenderings - latest dispach not changed state
Of course dispatch from other component will force update in this component ... if value will be different.
![Nam Le](https://lh5.googleusercontent.com/-O-Ru5nuaAa0/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3rdhRvOXW3kpMHBDX56WiTom9O5xtg/photo.jpg?sz=256)
Nam Le
Updated on June 10, 2022Comments
-
Nam Le about 2 years
I have experienced useEffect function from React hook. When I use it with useSelector from React-redux, it worked so weird.
My reducer:
const initialState = { a: 0 }; function mainReducer(state = initialState, action) { const { type, payload } = action; switch (type) { case 'A': return { ...state, a: payload } default: return state; } }
My Component:
function MyComponent(props) { const { a } = useSelector(state => state.mainReducer); const dispatch = useDispatch(); useEffect(() => { console.log('did mount: ', a); dispatch({ type: 'A', payload: 1 }) }, []); useEffect(() => { console.log('use effect: ', a); dispatch({ type: 'A', payload: a }); }, [a]) return (<View style={styles.container}> <Text style={styles.text}>{a}</Text> </View>); };
Result
Log:
did mount ran: 0 useEffect ran: 0
The last result is variable 'a' = 0
????
As I understand, After the first render, both effect ran sequentially in their order in the code.
(Step 1) So the first effect run fist -> log 'did mount ran: 0'. Then it dispatch value 1 to store
(Step 2) The second effect run after -> log 'did mount ran: 0'. Then it dispatch value 0 to storeBut what I don't understand is the second effect must track the change from variable 'a', so there will be:
In the following render time:
(Step 3) the second useEffect should be run when the value 'a' change from 0 to 1 (from Step 1).
And then:
(Step 4) it should have the third re-render when the value change again from 1 to 0 (from Step 2)So the log should be:
did mount ran: 0 useEffect ran: 0 useEffect ran: 1 useEffect ran: 0
Could you please explain to me what I'm missing? Thank you