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 hasn't changed.
Answer from Amit Chauhan on Stack OverflowYour 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 hasn't changed.
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'areaded from state on the beginning of render did mount: 0// 'old'a
// dispatch1... changed state in redux store.... rendered text
0
...
...//
useSelectorforces rerendering - change detectedrender: 1// latest dispatched value, processed by reducers into new state, rereaded by selectoruse effect: 1//useEffectworks AS EXPECTED as an effect ofachange- .... 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.
Bug: useEffect closure not called when dependencies changed
Bug: useEffect is triggered even if the array as dependency variable wasn't changed.
Useeffect not getting called immedietly as dependency value changes
React.useEffect not triggering when dependency has changed
Videos
Hello all, i'm a fairly noob developper and new to react.
Is it possible to have a useEffect to only run when the dependency array changes and not at mount ?
Also i can't explain why but it seems to me a bad use of useEffect, is there a better way to achieve this ? Thanks
React does state updates in batches. Which means, when you are setting state multiple times, it will update both the state in a single operation, resulting in reduced re-rending (which is good in most of the cases). You can learn more about this here.
When setState is called multiple times in React event handler or synchronous lifecycle method, it will be batched into a single update. That's why you are getting two logs, initial render causes first log and setState causes second log and when you called useState inside setTimeOut then it logged as you expected because setTimeOut is an asynchronous operation and it behaves like this with other asynchronous operations such as async/await, then/catch, fetch, etc. because Separate state updates will not be batched in asynchronous operations.