mirror of
https://github.com/pmndrs/zustand.git
synced 2025-12-08 19:45:52 +00:00
Merge branch 'main' into v5
This commit is contained in:
commit
4de1d1ff29
4
.github/workflows/test-multiple-versions.yml
vendored
4
.github/workflows/test-multiple-versions.yml
vendored
@ -32,8 +32,8 @@ jobs:
|
||||
- 18.0.0
|
||||
- 18.1.0
|
||||
- 18.2.0
|
||||
- 18.3.0-canary-2f8f77602-20240229
|
||||
- 0.0.0-experimental-2f8f77602-20240229
|
||||
- 19.0.0-rc-8f3c0525f9-20240521
|
||||
- 0.0.0-experimental-8f3c0525f9-20240521
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: pnpm/action-setup@v2
|
||||
|
||||
@ -80,9 +80,9 @@ const useBoundStore = create<{ foo: number }>()((_, get) => ({
|
||||
|
||||
This code compiles. But if we run it, we'll get an exception: "Uncaught TypeError: Cannot read properties of undefined (reading 'foo')". This is because `get` would return `undefined` before the initial state is created (hence you shouldn't call `get` when creating the initial state). The types promise that `get` will never return `undefined` but it does initially, which means Zustand failed to implement it.
|
||||
|
||||
And of course Zustand failed because it's impossible to implement `create` the way types promise (in the same way it's impossible to implement `createFoo`). In other words we don't have a type to express the actual `create` we have implemented. We can't type `get` as `() => T | undefined` because it would cause inconveince and it still won't be correct as `get` is indeed `() => T` eventually, just if called synchronously it would be `() => undefined`. What we need is some kind of TypeScript feature that allows us to type `get` as `(() => T) & WhenSync<() => undefined>`, which of course is extremly far-fetched.
|
||||
And of course Zustand failed because it's impossible to implement `create` the way types promise (in the same way it's impossible to implement `createFoo`). In other words we don't have a type to express the actual `create` we have implemented. We can't type `get` as `() => T | undefined` because it would cause inconvenience and it still won't be correct as `get` is indeed `() => T` eventually, just if called synchronously it would be `() => undefined`. What we need is some kind of TypeScript feature that allows us to type `get` as `(() => T) & WhenSync<() => undefined>`, which of course is extremely far-fetched.
|
||||
|
||||
So we have two problems: lack of inference and unsoundness. Lack of inference can be solved if TypeScript can improves its inference for invariants. And unsoundness can be solved if TypeScript introduces something like `WhenSync`. To work around lack of inference we manually annotate the state type. And we can't work around unsoundness, but it's not a big deal because it's not much, calling `get` synchronously anyway doesn't make sense.
|
||||
So we have two problems: lack of inference and unsoundness. Lack of inference can be solved if TypeScript can improve its inference for invariants. And unsoundness can be solved if TypeScript introduces something like `WhenSync`. To work around lack of inference we manually annotate the state type. And we can't work around unsoundness, but it's not a big deal because it's not much, calling `get` synchronously anyway doesn't make sense.
|
||||
|
||||
</details>
|
||||
|
||||
@ -208,7 +208,7 @@ const useBearStore = create<BearState>()(
|
||||
)
|
||||
```
|
||||
|
||||
Also, we recommend using `devtools` middleware as last as possible. For example, when you use it with `immer` as a middleware, it should be `immer(devtools(...))` and not `devtools(immer(...))`. This is because`devtools` mutates the `setState` and adds a type parameter on it, which could get lost if other middlewares (like `immer`) also mutate `setState` before `devtools`. Hence using `devtools` at the end makes sure that no middlewares mutate `setState` before it.
|
||||
Also, we recommend using `devtools` middleware as last as possible. For example, when you use it with `immer` as a middleware, it should be `devtools(immer(...))` and not `immer(devtools(...))`. This is because`devtools` mutates the `setState` and adds a type parameter on it, which could get lost if other middlewares (like `immer`) also mutate `setState` before `devtools`. Hence using `devtools` at the end makes sure that no middlewares mutate `setState` before it.
|
||||
|
||||
## Authoring middlewares and advanced usage
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@ This can be done using third-party libraries created by the community.
|
||||
|
||||
- [@dhmk/zustand-lens](https://github.com/dhmk083/dhmk-zustand-lens) — Lens support for Zustand.
|
||||
- [@liveblocks/zustand](https://github.com/liveblocks/liveblocks/tree/main/packages/liveblocks-zustand) — Liveblocks middleware to make your application multiplayer.
|
||||
- [@prncss-xyz/zustand-optics](https://github.com/prncss-xyz/zustand-optics) — An adapter for [optics-ts](https://github.com/akheron/optics-ts).
|
||||
- [auto-zustand-selectors-hook](https://github.com/Albert-Gao/auto-zustand-selectors-hook) — Automatic generation of Zustand hooks with Typescript support.
|
||||
- [derive-zustand](https://github.com/zustandjs/derive-zustand) — A function to create a derived Zustand store from other Zustand stores.
|
||||
- [geschichte](https://github.com/BowlingX/geschichte) — Zustand and Immer-based hook to manage query parameters.
|
||||
|
||||
42
package.json
42
package.json
@ -73,7 +73,7 @@
|
||||
"test:format": "prettier '*.{js,json,md}' '{examples,src,tests,docs}/**/*.{js,jsx,ts,tsx,md,mdx}' --list-different",
|
||||
"test:types": "tsc --noEmit",
|
||||
"test:lint": "eslint --no-eslintrc --c .eslintrc.json '*.{js,json,ts}' '{src,tests}/**/*.{ts,tsx}'",
|
||||
"test:spec": "vitest",
|
||||
"test:spec": "vitest run",
|
||||
"patch-d-ts": "node -e \"var {entries}=require('./rollup.config.js');require('shelljs').find('dist/**/*.d.ts').forEach(f=>{entries.forEach(({find,replacement})=>require('shelljs').sed('-i',new RegExp(' from \\''+find.source.slice(0,-1)+'\\';$'),' from \\''+replacement+'\\';',f));require('shelljs').sed('-i',/ from '(\\.[^']+)\\.ts';$/,' from \\'\\$1\\';',f)})\"",
|
||||
"copy": "shx cp -r dist/src/* dist/esm && shx cp -r dist/src/* dist && shx rm -rf dist/src && shx rm -rf dist/{src,tests} && shx cp package.json readme.md LICENSE dist && json -I -f dist/package.json -e \"this.private=false; this.devDependencies=undefined; this.optionalDependencies=undefined; this.scripts=undefined; this.prettier=undefined;\"",
|
||||
"patch-old-ts": "shx touch dist/ts_version_4.5_and_above_is_required.d.ts",
|
||||
@ -115,38 +115,38 @@
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-replace": "^5.0.5",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@testing-library/react": "^14.2.1",
|
||||
"@types/node": "^20.11.24",
|
||||
"@types/react": "^18.2.61",
|
||||
"@types/react-dom": "^18.2.19",
|
||||
"@testing-library/react": "^15.0.7",
|
||||
"@types/node": "^20.12.12",
|
||||
"@types/react": "^18.3.2",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/use-sync-external-store": "^0.0.6",
|
||||
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
||||
"@typescript-eslint/parser": "^7.1.0",
|
||||
"@vitest/coverage-v8": "^1.4.0",
|
||||
"@vitest/ui": "^1.4.0",
|
||||
"esbuild": "^0.20.1",
|
||||
"eslint": "^8.57.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.10.0",
|
||||
"@typescript-eslint/parser": "^7.10.0",
|
||||
"@vitest/coverage-v8": "^1.6.0",
|
||||
"@vitest/ui": "^1.6.0",
|
||||
"esbuild": "^0.21.3",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-vitest": "^0.3.22",
|
||||
"immer": "^10.0.3",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-vitest": "^0.5.4",
|
||||
"immer": "^10.1.1",
|
||||
"jsdom": "^24.0.0",
|
||||
"json": "^11.0.0",
|
||||
"prettier": "^3.2.5",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react": "19.0.0-rc-81c5ff2e04-20240521",
|
||||
"react-dom": "19.0.0-rc-81c5ff2e04-20240521",
|
||||
"redux": "^5.0.1",
|
||||
"rollup": "^4.12.0",
|
||||
"rollup": "^4.17.2",
|
||||
"rollup-plugin-esbuild": "^6.1.1",
|
||||
"shelljs": "^0.8.5",
|
||||
"shx": "^0.3.4",
|
||||
"typescript": "^5.3.3",
|
||||
"use-sync-external-store": "^1.2.0",
|
||||
"vitest": "^1.4.0"
|
||||
"typescript": "^5.4.5",
|
||||
"use-sync-external-store": "^1.2.2",
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=18.0.0",
|
||||
|
||||
632
pnpm-lock.yaml
generated
632
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user