Recoil state updates are out of sync with React component state
See original GitHub issueRecoil version: 0.3.1 React version: 17.0.2
If a component has both Recoil state and React component state, and both are updated at once, a full render will occur (including effects and committing to the DOM) with the old Recoil state and the new React component state, before re-rendering with the new Recoil state.
This still occurs when:
- unstable_batchedUpdates is used
- React 18 alpha is used (even with
ReactDOM.createRoot
)
Example code
import { atom, useRecoilState } from "recoil";
import React, { useEffect, useState } from "react";
const indexAtom = atom({
key: "index",
default: 0
});
export const TestComponent = () => {
const [stateIndex, setStateIndex] = useState(0);
const [recoilIndex, setRecoilIndex] = useRecoilState(indexAtom);
useEffect(() => {
console.log("=== Effect from render ===");
console.log("Local state: ", stateIndex);
console.log("Recoil state: ", recoilIndex);
});
return (
<button
onClick={() => {
setRecoilIndex(recoilIndex + 1);
setStateIndex(stateIndex + 1);
}}
>
Local state: {stateIndex} <br />
Recoil state: {recoilIndex}
</button>
);
};
When clicking the button, you’ll see the following being output:
=== Effect from render ===
Local state:
0
Recoil state:
0
=== Effect from render ===
Local state:
1
Recoil state:
0
=== Effect from render ===
Local state:
1
Recoil state:
1
Notice how on the second effect, local state and recoil state are different, despite being set to the same value on the same call.
I would expect the second effect to never occur - if component state and Recoil state are set simultaneously, they should be updated atomically.
Codesandbox demo: https://codesandbox.io/s/sharp-https-3ydwz?file=/src/TestComponent.js
Issue Analytics
- State:
- Created 2 years ago
- Reactions:7
- Comments:14 (5 by maintainers)
Top GitHub Comments
Same as above, as we are heavily relying on this feature 😃 We might be misusing things, but I find it very convenient to use useState and useRecoilState interchangeably in conjunction with useEffect.
If you can’t wait for the fix, you could patch-package 0.4.0 by enabling the feature flag and install react@next and react-dom@next which includes the requisite useMutableSource hook. I get a warning about not using the newer ReactDOM.createRoot API so it’ll behave like React 17 which is fine by me as I’m not ready to opt into concurrent mode.