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 ?
Maybe this ordering on "exports" can be changed for RN users of zustand ?
@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?
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?
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?
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.
@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
https://www.npmjs.com/package/zustand/v/5.0.0-beta.0 is published!
Migration Guide: https://github.com/pmndrs/zustand/blob/v5/docs/guides/migrating-to-v5.mdx
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
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.