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)

Most upvoted comments

@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 how useReducer 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

This behaviour causes performance issues in one of my apps

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?

Is there a way to prevent this issue?

For now, I don’t have a solution, but maybe spend some time to see if there are any better solutions.