-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* prepare for the next major version * [v5] breaking: drop default exports (#2238) * fix: drop default exports for v5 * chore: remove default from cjs build * refactor: export shallow in v5 * fix: remove `addModuleExport` option for cjs. * [v5] breaking: drop deprecated features (#2235) * fix: remove deprecated v4 features * chore(build): remove context * docs(typescript): remove deprecated equals api * docs(persist): remove old persist api * chore: run yarn prettier on typescript docs * Discard changes to docs/guides/typescript.md * Discard changes to docs/integrations/persisting-store-data.md * Discard changes to tests/shallow.test.tsx * Discard changes to tests/vanilla/subscribe.test.tsx * [v5] breaking: make React 18 as minimal requirement (#2236) * fix: update package.json to require react 18+ * chore: update github actions to test on react 18+ * chore: remove devtools-skip hack from actions * chore(test): remove CI-SKIP from devtools tests * [v5] breaking: make use-sync-external-store an optional peer dependency (#2237) * chore: make use-sync-external-store optional peerDep * fix: use correct versions in package.json * [v5] breaking: require TypeScript 4.5 and update tests (#2257) * breaking(types): TS requirement * wip: latest only * wip: latest only 2 * drop ts <4.4 * wip: do not skip lib checkes * use latest node types * drop ts 4.4 * [v5]: drop "module" condition (#2270) * Update package json in order to remove module * Update rollup config in order to remove module config * Update patch esm script * Update package json to general exports and update node version (#2272) * [v5]: drop UMD/SystemJS builds (#2287) * Update rollup config in order to drop system js and umd builds * Update packages * Clean up files * Update rollup config * Update gh workflows * Minor fixes * Minor fixes * Minor fixes * Minor fixes * Testing * Minor changes * Minor fixes * remove `WithReact` type (#2300) * 5.0.0-alpha.0 * [v5]: do not depend on use-sync-external-store (#2301) * [v5]: do not depend on use-sync-external-store * memo get(server)snapshot * 5.0.0-alpha.1 * [v5]: refactor useMemoSelector (#2302) * [v5]: refactor useMemoSelector * add a test * Revert "[v5]: refactor useMemoSelector" This reverts commit b3c8b15. * Revert "Revert "[v5]: refactor useMemoSelector"" This reverts commit 3c47301. * [v5]: separate react entry point (#2303) * 5.0.0-alpha.2 * 5.0.0-alpha.3 * refactor: Switch to Object.hasOwn (#2365) * [v5] drop es5 (#2380) * update yarn lock * 5.0.0-alpha.4 * [v5]: follow React "standard" way with breaking behavioral change (#2395) * [v5]: follow React "standard" way with breaking behavioral change * add test * 5.0.0-alpha.5 * [v5] Rewrite shallow to support iterables (#2427) * [v5] fix rollup config for cjs (#2433) * 5.0.0-alpha.6 * no production build test * recover types that are dropped in #2462 * remove unused replacement * [v5] Remove Devtools warning (#2466) * chore: remove devtools extension warning * docs: add devtools link to readme * chore: remove unused test * chrome: remove unused tests * chore: remove unused test * Revert "chore: remove unused test" This reverts commit 0fa2a75. * update test name * update pnpm lock * fix merge main * add migration guide * fix typos * 5.0.0-beta.0 * update migration doc * fix merge main * fix merge main (prettier) * 5.0.0-beta.1 * fix(types)!: require complete state if `setState`'s `replace` flag is set (#2580) * fix(types): require complete state if `setState`'s `replace` flag is set * switch to variant 2 * fix type errors * update setState types for devtools and immer * make devtools setState non-generic * add migration guide * merge migration guides * run prettier * Update tests/middlewareTypes.test.tsx --------- Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com> Co-authored-by: daishi <daishi@axlight.com> * 5.0.0-beta.2 * move v5 migration doc * fix ci * missing commmit * remove unused rule exclusion * comment about react compiler * revert eslint config --------- Co-authored-by: Charles Kornoelje <33156025+charkour@users.noreply.github.com> Co-authored-by: Danilo Britto <dbritto.dev@gmail.com> Co-authored-by: Ekin Dursun <ekindursun@gmail.com> Co-authored-by: Simon Farshid <simon.farshid@outlook.com>
- Loading branch information
1 parent
53e5a2a
commit e247220
Showing
29 changed files
with
523 additions
and
2,560 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
--- | ||
title: 'How to Migrate to v5 from v4' | ||
nav: 30 | ||
--- | ||
|
||
# How to Migrate to v5 from v4 | ||
|
||
We highly recommend to update to the latest version of v4, before migrating to v5. It will show all deprecation warnings without breaking your app. | ||
|
||
## Changes in v5 | ||
|
||
- Drop default exports | ||
- Drop deprecated features | ||
- Make React 18 the minimum required version | ||
- Make use-sync-external-store a peer dependency (required for `createWithEqualityFn` and `useStoreWithEqualityFn` in `zustand/traditional`) | ||
- Make TypeScript 4.5 the minimum required version | ||
- Drop UMD/SystemJS support | ||
- Organize entry points in the package.json | ||
- Drop ES5 support | ||
- Stricter types when setState's replace flag is set | ||
- Other small improvements (technically breaking changes) | ||
|
||
## Migration Guide | ||
|
||
### Using custom equality functions such as `shallow` | ||
|
||
The `create` function in v5 does not support customizing equality function. | ||
|
||
If you use custom equality function such as `shallow`, | ||
the easiest migration is to use `createWithEqualityFn`. | ||
|
||
```js | ||
// v4 | ||
import { create } from 'zustand' | ||
import { shallow } from 'zustand/shallow' | ||
|
||
const useCountStore = create((set) => ({ | ||
count: 0, | ||
text: 'hello', | ||
// ... | ||
})) | ||
|
||
const Component = () => { | ||
const { count, text } = useCountStore( | ||
(state) => ({ | ||
count: state.count, | ||
text: state.text, | ||
}), | ||
shallow, | ||
) | ||
// ... | ||
} | ||
``` | ||
|
||
That can be done with `createWithEqualityFn` in v5: | ||
|
||
```bash | ||
npm install use-sync-external-store | ||
``` | ||
|
||
```js | ||
// v5 | ||
import { createWithEqualityFn as create } from 'zustand/traditional' | ||
|
||
// The rest is the same as v4 | ||
``` | ||
|
||
Alternatively, for the `shallow` use case, you can use `useShallow` hook: | ||
|
||
```js | ||
// v5 | ||
import { create } from 'zustand' | ||
import { useShallow } from 'zustand/shallow' | ||
|
||
const useCountStore = create((set) => ({ | ||
count: 0, | ||
text: 'hello', | ||
// ... | ||
})) | ||
|
||
const Component = () => { | ||
const { count, text } = useCountStore( | ||
useShallow((state) => ({ | ||
count: state.count, | ||
text: state.text, | ||
})), | ||
) | ||
// ... | ||
} | ||
``` | ||
|
||
### Requiring stable selector outputs | ||
|
||
There is a behavioral change in v5 to match React default behavior. | ||
If a selector returns a new reference, it may cause infinite loops. | ||
|
||
For example, this may cause infinite loops. | ||
|
||
```js | ||
// v4 | ||
const action = useMainStore((state) => { | ||
return state.action ?? () => {} | ||
}) | ||
``` | ||
The error message will be something like this: | ||
``` | ||
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. | ||
``` | ||
To fix it, make sure the selector function returns a stable reference. | ||
```js | ||
// v5 | ||
|
||
const FALLBACK_ACTION = () => {} | ||
|
||
const action = useMainStore((state) => { | ||
return state.action ?? FALLBACK_ACTION | ||
}) | ||
``` | ||
Alternatively, if you need v4 behavior, `createWithEqualityFn` will do. | ||
```js | ||
// v5 | ||
import { createWithEqualityFn as create } from 'zustand/traditional' | ||
``` | ||
### Stricter types when setState's replace flag is set (Typescript only) | ||
```diff | ||
- setState: | ||
- (partial: T | Partial<T> | ((state: T) => T | Partial<T>), replace?: boolean | undefined) => void; | ||
+ setState: | ||
+ (partial: T | Partial<T> | ((state: T) => T | Partial<T>), replace?: false) => void; | ||
+ (state: T | ((state: T) => T), replace: true) => void; | ||
``` | ||
If you are not using the `replace` flag, no migration is required. | ||
If you are using the `replace` flag and it's set to `true`, you must provide a complete state object. | ||
This change ensures that `store.setState({}, true)` (which results in an invalid state) is no longer considered valid. | ||
**Examples:** | ||
```ts | ||
// Partial state update (valid) | ||
store.setState({ key: 'value' }) | ||
|
||
// Complete state replacement (valid) | ||
store.setState({ key: 'value' }, true) | ||
|
||
// Incomplete state replacement (invalid) | ||
store.setState({}, true) // Error | ||
``` | ||
#### Handling Dynamic `replace` Flag | ||
If the value of the `replace` flag is dynamic and determined at runtime, you might face issues. To handle this, you can use a workaround by annotating the `replace` parameter with `as any`: | ||
```ts | ||
const replaceFlag = Math.random() > 0.5 | ||
store.setState(partialOrFull, replaceFlag as any) | ||
``` | ||
## Links | ||
- https://github.com/pmndrs/zustand/pull/2138 | ||
- https://github.com/pmndrs/zustand/pull/2580 |
Oops, something went wrong.