Skip to content

ink + zustand not re-rendering #539

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mattrothenberg opened this issue Nov 21, 2022 · 3 comments
Closed

ink + zustand not re-rendering #539

mattrothenberg opened this issue Nov 21, 2022 · 3 comments

Comments

@mattrothenberg
Copy link

mattrothenberg commented Nov 21, 2022

Hello!

Note
TL;DR: components that read values from zustand don't re-render unless an additional render is forced via, say, a useState setter function.

I've discovered an odd behavior while implementing an Ink CLI that uses zustand for global state management.

In summary, I've noticed that components that read values from my Zustand store do not re-render in a predictable manner. "Predictable" in the sense that the same (well, similar, since we're dealing with the DOM) code works totally fine in the browser, but not in the CLI environment.

Here's the issue. I'm storing a global value (let's call it fruit) in Zustand and I expose a select control to end users so that they can update this global value. I expect that when users arrow up or down to a value and press "Enter," the global state updates.

Reproduction Repo: https://github.com/mattrothenberg/ink-zustand-test

No update 😭
CleanShot 2022-11-21 at 18 52 28

In the browser, this similar code works totally fine.

Reproduction CodeSandbox: https://codesandbox.io/s/staging-violet-zog39y?file=/src/App.tsx
CleanShot 2022-11-21 at 18 59 13

I've noticed, however, that when I trigger an unrelated state update in my component as well, I do see my component re-render and the new global state is reflected in the CLI.

Hooray 🎉
CleanShot 2022-11-21 at 19 06 30

const useAppStore = create<AppStore>((set) => ({
  fruit: "mango",
  setFruit: (newFruit) => {
    set(() => ({ fruit: newFruit }));
  },
}));

const App = () => {
  const { fruit, setFruit } = useAppStore();
  const [_, setState] = useState(0);

  return (
    <Box flexDirection="column">
      <Text>Selected fruit: {fruit}</Text>
      <SelectInput
        items={["apple", "mango", "orange", "pineapple"].map((mode) => {
          return {
            label: mode,
            value: mode,
          };
        })}
        onSelect={(item) => {
          setFruit(item.value);
          // it 'works' 🤣
          setState((curr) => curr + 1);
        }}
      />
    </Box>
  );
};

Do you have any ideas why this might be happening? I fully expect any call to my Zustand update functions to trigger a re-render for any components that read from the same store.

Thank you!

@mattrothenberg
Copy link
Author

Temporary fix: https://github.com/dai-shi/use-zustand

@ceuk
Copy link

ceuk commented Jan 2, 2023

Just to add to this - useSelector from react-redux also doesn't trigger re-render. e.g.

const items = useSelector(state => state.items) 

return (
   {items.map(...)}
) 

Will not re-render when items is updated. However, as OP mentions, if I trigger a re-render by other means, it works

@vadimdemedes
Copy link
Owner

vadimdemedes commented Mar 3, 2023

This looks like a similar issue → #535. Any chance Zustand does something similar to Valtio and has two entrypoints for client / server, which behave differently?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants