pmndrs / zustand

🐻 Bear necessities for state management in React

Home Page:https://zustand-demo.pmnd.rs/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RFC: How is v5-alpha/beta?

dai-shi opened this issue Β· comments

Zustand v5 is being developed #2138 and some alpha versions have been published.

We need more feedback before going beta, and releasing it finally.

npm i zustand@next

Please add reactions to this issue:
πŸ‘ : I tested v5-alpha in my project and it works fine.
πŸ‘Ž : I tested v5-alpha in my project and it fails. < Comment below!
πŸ‘€ : I'm going to try it ASAP.

5.0.0-alpha.4 is published. πŸ‘ / πŸ‘Ž / πŸ‘€

5.0.0-alpha.5 is published. πŸ‘ / πŸ‘Ž / πŸ‘€

5.0.0-alpha.5 works with zundo@2.1.0

5.0.0-alpha.6 is published. CJS build was broken in alpha.4 and alpha.5.

5.0.0-alpha.6 works fine! Even resolves my react-native described here #1967

Maybe this ordering on "exports" can be changed for RN users of zustand ?

#1967 (reply in thread)

Maybe this ordering on "exports" can be changed for RN users of zustand ?

#1967 (reply in thread)

@jacargentina let me take care of that

@dbritto-dev I've solved it by configuring in metro.config.js:

config.resolver.unstable_conditionNames = ['require'];

default is ['require', 'import'] so that import was causing my problem.

@jacargentina nice, I found that yesterday too but I didn't have time to answer any question. We shall add it to the docs.

Does the readme of the v5 branch already reflect the changes that will be coming up in v5 or is there some other place where one could read about it?

#2138

@flq here you go -> #2138

commented

5.0.0-alpha.6 fails

5.0.0-alpha.5 fails

image

5.0.0-alpha.4 work fine
image

Thanks for reporting.
It's an intentional breaking change in #2395.
We would like to add a note in migration guide in docs. Can you create a minimal reproduction to help the docs?

commented

Can you create a minimal reproduction to help the docs?

I will create an example later.


I can first describe how I encountered this problem.

I first migrated from redux toolkit to zustand^4 and everything worked fine.
Then I upgraded zustand@5.0.0-alpha.6

The reason for this problem may be that Redux useSelector's callback do'not need to be wrapped by useCallback.

After #2395, which may have caused the issue.

Maybe useSyncExternalStoreWithSelector would be more suitable?

commented

https://stackblitz.com/edit/vitejs-vite-qvlgmz?file=src%2Fcomponents%2FTodolist.tsx

@dai-shi I have create a todo list demo with this bug.

The reason why it fails is because of the use of the useTodoFindIds function.

Of course, the actual scenario is more complicated than what is written here. I want to find a set of data and then return their IDs.

I'm not sure if some best practices were violated that caused this problem?

I'm not sure if some best practices were violated that caused this problem?

Yes, you create a new reference every time in your selector function.

// an easy reproduction
const useFooStore = create((set) => ({
  todos: [],
}))

  // this will cause an infinite loop because of new reference every render
  useFooStore((state) => state.todos.map((todo) => todo.id))

To resolve it, either use createWithEqualityFn & shallow or useShallow.

This infinite-loop behavior can happen without Zustand, and Zustand follows the same behavior.

commented

After using reselect, this problem was also solved.

image

For RTK users migrating to zustand@next. Maybe be more familiar with reselect.

I think this can be added to the migration manual.

@flq yeah, I'll add it. btw, they talk about memoizing selectors.

After using reselect, this problem was also solved.

FYI, proxy-memoize also works. https://redux.js.org/usage/deriving-data-selectors#proxy-memoize

May post a reproduction when I find the time, but as a general note, I've been getting a ton of

Warning: The result of getSnapshot should be cached to avoid an infinite loop

and

Uncaught 
Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

errors after migrating from the latest version of v4 to v5 beta

EDIT: Found the cause

// v4

const selectAction = (state: MainStore) => {
	return state.action ?? () => {};
};


const Component = () => {
	const action = useMainStore(selectAction);
	...
}
// v5

const FALLBACK_ACTION = () => {};

const selectAction = (state: MainStore) => {
	return state.action ?? FALLBACK_ACTION;
};

const Component = () => {
	const action = useMainStore(selectAction);
	...
}

Thanks for reporting. It's an intentional change in #2395.
We should write something in the migration doc.

πŸ‘‰ c79d3fd

Thanks for reporting. It's an intentional change in #2395. We should write something in the migration doc.

πŸ‘‰ c79d3fd

Also ran into the same error when combing Zustand with proxy-memoize v3 that didn't occur before. Not exactly sure how to solve this one.

const fn = memoize(x => ({ sum: x.a + x.b, diff: x.a - x.b }));

...
// true
fn({ a: 1, b: 2, c: 1 }) === fn({ a: 1, b: 2, c: 5 })

// success
const test = useMainStore((state) => fn({ a: 1, b: 2, c: 1 }));

// success
const test = useMainStore((state) => fn({ a: 1, b: 2, c: 1 }));
const test2 = useMainStore((state) => fn({ a: 1, b: 2, c: 1 }));

// success
const test = useMainStore((state) => fn({ a: 1, b: 2, c: 1 }));
const test2 = useMainStore((state) => fn({ a: 1, b: 2, c: 5 }));

// error
const test = useMainStore((state) => fn({ a: 1, b: 2, c: 1 }));
const test2 = useMainStore((state) => fn({ a: 1, b: 100, c: 5 }));
// If c is touched, but result is the same 
const fn = memoize(x => ({ sum: x.a + x.b, diff: x.a - x.b - x.c + x.c }));

// false
fn({ a: 1, b: 2, c: 1 }) === fn({ a: 1, b: 2, c: 5 })

// error
const test = useMainStore((state) => fn({ a: 1, b: 2, c: 1 }));
const test2 = useMainStore((state) => fn({ a: 1, b: 2, c: 5 }));

Also ran into the same error when combing Zustand with proxy-memoize v3 that didn't occur before.

That sounds unexpected. Can you create a small reproduction with stackblitz?

Also ran into the same error when combing Zustand with proxy-memoize v3 that didn't occur before.

That sounds unexpected. Can you create a small reproduction with stackblitz?

https://stackblitz.com/edit/vitejs-vite-ob9acn?file=src%2FApp.tsx

https://stackblitz.com/edit/vitejs-vite-ob9acn?file=src%2FApp.tsx

Thanks. Now I get it. It the usage issue of proxy-memoze. By default, memoize only remembers the last result. To work it around, you need to specify size option.
https://stackblitz.com/edit/vitejs-vite-9onv6a?file=src%2FApp.tsx

In other words, zustand v5 reveals the issue which was hidden in v4, and with the new one, it performs better.