pmndrs / jotai

👻 Primitive and flexible state management for React
https://jotai.org
MIT License
18.25k stars 590 forks source link

React 18 & focusAtom: render bail out not working as expected #1256

Closed mdugue closed 2 years ago

mdugue commented 2 years ago

I am looking for a solution to change a part of a nested global state without triggering renders for components that only consume another unchanged part of that global state.

As I understand the docs focusAtom is what I actually need. Unfortunately this is working fine for react 17 but not 18. Can you provide any background to that? Is that a temporary issue? On purpose? Is there a roadmap on solving it in case? I found https://github.com/pmndrs/jotai/discussions/1218 but was not sure if this actually relates.

I created a super simple example, expecting to only log rendering first when the first components input is changed and rendering second when the other is changed.

React 17 (working) https://codesandbox.io/s/jotai-focusatom-react17-3eonpi React 18 (not working) https://codesandbox.io/s/jotai-focusatom-react18-broken-0nlwrg

Here my code:


import { atom, useAtom } from "jotai";
import { focusAtom } from "jotai/optics";

const textAtom = atom({ first: "test1", second: "test2" });

const firstAtom = focusAtom(textAtom, (optic) => optic.prop("first"));
const secondAtom = focusAtom(textAtom, (optic) => optic.prop("second"));

const First = () => {
  const [value, set] = useAtom(firstAtom);
  console.log("rendering first");

  return (
    <div>
      <input value={value} onChange={(e) => set(() => e.target.value)} />
      <div>first: {value}</div>
    </div>
  );
};

const Second = () => {
  const [value, set] = useAtom(secondAtom);
  console.log("rendering second");

  return (
    <div>
      <input value={value} onChange={(e) => set(() => e.target.value)} />
      <div>second: {value}</div>
    </div>
  );
};

export const JotaiTest = () => {
  return (
    <>
      <First />
      <Second />
    </>
  );
};

Happy for any hints if I misunderstand some concepts, if I can fix this behavior or whatsoever ✌️

dai-shi commented 2 years ago

It's working as intended. It's not an issue. You can wrap console.log with useEffect to get more intuitive output.

This is the change in React not in jotai. See this example: https://twitter.com/dai_shi/status/1534170089981100032

Closing it but this is something others may ask, so it might be a good idea to note something in docs somewhere.