I was playing around with React Context API and found that the provider renders twice at each value change.
Here is what I've done.
The problem ?
Each time I hit the button to change the context value, the provider renders twice, but the effect is executed only once.
So the ref is incremented always twice, but the effect only gets the last value each time (it skips a value!).
Also, at the first render of the provider it logs twice the same ref value, which is very strange to me.
Can anybody tell me why I am getting this behavior ?
Here is the code:
The provider:
const MyContext = React.createContext(0);
function Provider({ children }) {
const state = React.useState("Yes");
const ref = React.useRef(0);
ref.current += 1;
console.log("Context provider ", ref.current);
React.useEffect(() => {
console.log("effect on provider, ref value = ", ref.current);
});
return <MyContext.Provider value={state}>{children}</MyContext.Provider>;
}
The two children
function DirectChild({ children }) {
console.log("provider direct child");
return children;
}
function Consumer() {
console.log("consumer");
const [state, setState] = React.useContext(MyContext);
return (
<div>
<span>State value: {state}</span>
<br />
<button onClick={() => setState(old => old + "Yes")}>Change</button>
</div>
);
}
The App
export default function App() {
console.log("APP");
return (
<Provider>
<DirectChild>
<Consumer />
</DirectChild>
</Provider>
);
}
Here is a codesandbox demo
Found the reason,
There is no bug, and no strange behavior, I was just missing that codesandbox by default renders the App within a React.StrictMode
parent.
First, I ported the code to my local project, then observed that there was no issues.
Searched over codesandbox repo issues and found that it is linked to a react behavior on strict mode:
It is expected that setState updaters will run twice in strict mode in development. This helps ensure the code doesn't rely on them running a single time (which wouldn't be the case if an async render was aborted and alter restarted). If your setState updaters are pure functions (as they should be) then this shouldn't affect the logic of your application.
Codesandbox issue
React issue
But still, The effect is executed only once and misses my ref update.
EDIT
React 18 introduced strict effects, which runs effects also twice under strict mode in development.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With