Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: How is v5-alpha/beta? #2329

Open
dai-shi opened this issue Feb 13, 2024 · 24 comments
Open

RFC: How is v5-alpha/beta? #2329

dai-shi opened this issue Feb 13, 2024 · 24 comments

Comments

@dai-shi
Copy link
Member

dai-shi commented Feb 13, 2024

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.

@dai-shi
Copy link
Member Author

dai-shi commented Mar 2, 2024

5.0.0-alpha.4 is published. 馃憤 / 馃憥 / 馃憖

@dai-shi
Copy link
Member Author

dai-shi commented Mar 9, 2024

5.0.0-alpha.5 is published. 馃憤 / 馃憥 / 馃憖

@charkour
Copy link
Collaborator

5.0.0-alpha.5 works with [email protected]

@dai-shi
Copy link
Member Author

dai-shi commented Mar 23, 2024

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

@jacargentina
Copy link

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

@jacargentina
Copy link

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

#1967 (reply in thread)

@dbritto-dev
Copy link
Collaborator

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

#1967 (reply in thread)

@jacargentina let me take care of that

@jacargentina
Copy link

@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.

@dbritto-dev
Copy link
Collaborator

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

@flq
Copy link

flq commented Apr 15, 2024

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?

@dbritto-dev
Copy link
Collaborator

#2138

@flq here you go -> #2138

@cqh963852
Copy link

5.0.0-alpha.6 fails

5.0.0-alpha.5 fails

image

5.0.0-alpha.4 work fine
image

@dai-shi
Copy link
Member Author

dai-shi commented Apr 28, 2024

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?

@cqh963852
Copy link

cqh963852 commented Apr 29, 2024

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 [email protected]

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?

@cqh963852
Copy link

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?

@dai-shi
Copy link
Member Author

dai-shi commented May 5, 2024

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.

@cqh963852
Copy link

cqh963852 commented May 7, 2024

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.

@dbritto-dev
Copy link
Collaborator

dbritto-dev commented May 7, 2024

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

@dai-shi
Copy link
Member Author

dai-shi commented May 7, 2024

After using reselect, this problem was also solved.

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

@dai-shi
Copy link
Member Author

dai-shi commented May 22, 2024

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

@dai-shi dai-shi changed the title RFC: How is v5-alpha? RFC: How is v5-alpha/beta? May 22, 2024
@elson-currentcorp
Copy link

elson-currentcorp commented May 22, 2024

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);
	...
}

@dai-shi
Copy link
Member Author

dai-shi commented May 23, 2024

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

馃憠 c79d3fd

@elson-currentcorp
Copy link

elson-currentcorp commented May 23, 2024

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 }))

@dai-shi
Copy link
Member Author

dai-shi commented May 24, 2024

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?

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

7 participants