jotai: Avoid rerenders if atom value doesn't change
Currently a React Component that uses an readonly atom, gets always rerendered if one of the atoms dependencies changes. Even if the value of the atom is the same.
I created an example to demonstrate the issue:
https://codesandbox.io/s/jotai-rerender-demo-pgr5ep?file=/src/App.tsx
If you click the button, ComponentA
is always rendered, even if its atom value never changes.
This behaviour causes performance issues in one of my apps, which has a very big state (stateAtom
) that comes from the server and is therefore saved in one atom, and heavily uses selectAtom
to split the big state into smaller atoms. Everytime the stateAtom
is updated, most of the App gets rerendered, even if the state change affects just one component.
This sandbox demonstrates the same issue with selectAtom
:
https://codesandbox.io/s/jotai-rerender-demo-select-m3umz7
I expected that a component would only update if the value of the atom changes.
Is there a way to prevent this issue?
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 24 (11 by maintainers)
@dai-shi Thank you for the clarification! I didn’t now about the difference between the render and the commit phase.
I was able to find the source of my performance issues with the React profiler and a
useMemo
(as recommended).Off topic: Thank you for your great work on this library. I really love using it!
#1159 should fix the same value with non-derived atoms https://github.com/pmndrs/jotai/issues/1158#issuecomment-1126820506.
For derived atoms as originally reported, this is working as expected. The rationale is that the library doesn’t know how heavy
read
function is. So, we run it in “render” phase and then “bail out” if value isn’t changed. This is same as howuseReducer
works (especially in React 18).The solution for heavy computation is
useMemo
https://github.com/pmndrs/jotai/issues/1158#issuecomment-1126838547 or putting the computation in derived atoms.Closing this but I would love to hear the feedbacks.
Okay, what’s news to me is that React changes
useReducer
behavior with 18 (createRoot) and 17.https://codesandbox.io/s/eager-lake-khw3pw?file=/src/App.js
This is something being asked several times. #1015 #1137 #1155 See how it behaves: https://codesandbox.io/s/jotai-rerender-demo-forked-clne10
Now, this is a real problem. Thanks for sharing. My assumption is there are some heavy computations in a render function. Can you guess what they are? If so, wrapping with
useMemo
solves the problem, doesn’t it?For now, I don’t have a solution, but maybe spend some time to see if there are any better solutions.