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
39928ef973
4
.github/workflows/test-multiple-versions.yml
vendored
4
.github/workflows/test-multiple-versions.yml
vendored
@ -33,8 +33,8 @@ jobs:
|
||||
- 18.0.0
|
||||
- 18.1.0
|
||||
- 18.2.0
|
||||
- 18.3.0-canary-0c6348758-20231030
|
||||
- 0.0.0-experimental-0c6348758-20231030
|
||||
- 18.3.0-canary-6c7b41da3-20231123
|
||||
- 0.0.0-experimental-6c7b41da3-20231123
|
||||
devtools-skip:
|
||||
- CI-MATRIX-NOSKIP
|
||||
include:
|
||||
|
||||
2
.github/workflows/test-old-typescript.yml
vendored
2
.github/workflows/test-old-typescript.yml
vendored
@ -13,6 +13,8 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
typescript:
|
||||
- 5.3.2
|
||||
- 5.2.2
|
||||
- 5.1.6
|
||||
- 5.0.4
|
||||
- 4.9.5
|
||||
|
||||
@ -33,9 +33,7 @@ Zustand is available as a package on NPM for use:
|
||||
```bash
|
||||
# NPM
|
||||
npm install zustand
|
||||
|
||||
# Yarn
|
||||
yarn add zustand
|
||||
# Or, use any package manager of your choice.
|
||||
```
|
||||
|
||||
## First create a store
|
||||
|
||||
49
package.json
49
package.json
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "zustand",
|
||||
"private": true,
|
||||
"version": "4.4.6",
|
||||
"version": "4.4.7",
|
||||
"publishConfig": {
|
||||
"tag": "next"
|
||||
},
|
||||
@ -208,49 +208,49 @@
|
||||
"use-sync-external-store": "1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.2",
|
||||
"@babel/plugin-external-helpers": "^7.22.5",
|
||||
"@babel/plugin-transform-react-jsx": "^7.22.15",
|
||||
"@babel/plugin-transform-runtime": "^7.23.2",
|
||||
"@babel/plugin-transform-typescript": "^7.22.15",
|
||||
"@babel/preset-env": "^7.23.2",
|
||||
"@redux-devtools/extension": "^3.2.5",
|
||||
"@rollup/plugin-alias": "^5.0.1",
|
||||
"@babel/core": "^7.23.3",
|
||||
"@babel/plugin-external-helpers": "^7.23.3",
|
||||
"@babel/plugin-transform-react-jsx": "^7.23.4",
|
||||
"@babel/plugin-transform-runtime": "^7.23.4",
|
||||
"@babel/plugin-transform-typescript": "^7.23.4",
|
||||
"@babel/preset-env": "^7.23.3",
|
||||
"@redux-devtools/extension": "^3.2.6",
|
||||
"@rollup/plugin-alias": "^5.1.0",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@rollup/plugin-replace": "^5.0.5",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@rollup/plugin-typescript": "^11.1.5",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@types/react": "^18.2.33",
|
||||
"@types/react-dom": "^18.2.14",
|
||||
"@types/use-sync-external-store": "^0.0.5",
|
||||
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
||||
"@typescript-eslint/parser": "^6.9.1",
|
||||
"@vitest/coverage-c8": "^0.33.0",
|
||||
"@testing-library/react": "^14.1.2",
|
||||
"@types/react": "^18.2.39",
|
||||
"@types/react-dom": "^18.2.17",
|
||||
"@types/use-sync-external-store": "^0.0.6",
|
||||
"@typescript-eslint/eslint-plugin": "^6.13.0",
|
||||
"@typescript-eslint/parser": "^6.13.0",
|
||||
"@vitest/coverage-v8": "^0.34.6",
|
||||
"@vitest/ui": "^0.34.6",
|
||||
"concurrently": "^8.2.2",
|
||||
"downlevel-dts": "^0.11.0",
|
||||
"esbuild": "^0.19.5",
|
||||
"eslint": "^8.52.0",
|
||||
"esbuild": "^0.19.8",
|
||||
"eslint": "^8.54.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-plugin-import": "^2.29.0",
|
||||
"eslint-plugin-prettier": "^5.0.1",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-vitest": "^0.3.8",
|
||||
"eslint-plugin-vitest": "^0.3.10",
|
||||
"immer": "^10.0.3",
|
||||
"jsdom": "^22.1.0",
|
||||
"jsdom": "^23.0.0",
|
||||
"json": "^11.0.0",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier": "^3.1.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"redux": "5.0.0-alpha.1",
|
||||
"rollup": "^4.2.0",
|
||||
"rollup": "^4.6.0",
|
||||
"rollup-plugin-esbuild": "^6.1.0",
|
||||
"shx": "^0.3.4",
|
||||
"typescript": "^5.2.2",
|
||||
"typescript": "^5.3.2",
|
||||
"vitest": "^0.34.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@ -268,5 +268,8 @@
|
||||
"react": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"resolutions": {
|
||||
"vite": "4.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,6 +164,8 @@ const useSoundStore = create((set, get) => ({
|
||||
|
||||
Sometimes you need to access state in a non-reactive way or act upon the store. For these cases, the resulting hook has utility functions attached to its prototype.
|
||||
|
||||
:warning: This technique is not recommended for adding state in [React Server Components](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md) (typically in Next.js 13 and above). It can lead to unexpected bugs and privacy issues for your users. For more details, see [#2200](https://github.com/pmndrs/zustand/discussions/2200).
|
||||
|
||||
```jsx
|
||||
const useDogStore = create(() => ({ paw: true, snout: true, fur: true }))
|
||||
|
||||
|
||||
@ -30,22 +30,22 @@ type Write<T, U> = Omit<T, keyof U> & U
|
||||
type TakeTwo<T> = T extends { length: 0 }
|
||||
? [undefined, undefined]
|
||||
: T extends { length: 1 }
|
||||
? [...a0: Cast<T, unknown[]>, a1: undefined]
|
||||
: T extends { length: 0 | 1 }
|
||||
? [...a0: Cast<T, unknown[]>, a1: undefined]
|
||||
: T extends { length: 2 }
|
||||
? T
|
||||
: T extends { length: 1 | 2 }
|
||||
? T
|
||||
: T extends { length: 0 | 1 | 2 }
|
||||
? T
|
||||
: T extends [infer A0, infer A1, ...unknown[]]
|
||||
? [A0, A1]
|
||||
: T extends [infer A0, (infer A1)?, ...unknown[]]
|
||||
? [A0, A1?]
|
||||
: T extends [(infer A0)?, (infer A1)?, ...unknown[]]
|
||||
? [A0?, A1?]
|
||||
: never
|
||||
? [...a0: Cast<T, unknown[]>, a1: undefined]
|
||||
: T extends { length: 0 | 1 }
|
||||
? [...a0: Cast<T, unknown[]>, a1: undefined]
|
||||
: T extends { length: 2 }
|
||||
? T
|
||||
: T extends { length: 1 | 2 }
|
||||
? T
|
||||
: T extends { length: 0 | 1 | 2 }
|
||||
? T
|
||||
: T extends [infer A0, infer A1, ...unknown[]]
|
||||
? [A0, A1]
|
||||
: T extends [infer A0, (infer A1)?, ...unknown[]]
|
||||
? [A0, A1?]
|
||||
: T extends [(infer A0)?, (infer A1)?, ...unknown[]]
|
||||
? [A0?, A1?]
|
||||
: never
|
||||
|
||||
type WithDevtools<S> = Write<S, StoreDevtools<S>>
|
||||
|
||||
@ -53,7 +53,7 @@ type StoreDevtools<S> = S extends {
|
||||
setState: (...a: infer Sa) => infer Sr
|
||||
}
|
||||
? {
|
||||
setState<A extends string | { type: unknown }>(
|
||||
setState<A extends string | { type: string }>(
|
||||
...a: [...a: TakeTwo<Sa>, action?: A]
|
||||
): Sr
|
||||
}
|
||||
@ -173,12 +173,12 @@ const devtoolsImpl: DevtoolsImpl =
|
||||
;(api.setState as NamedSet<S>) = (state, replace, nameOrAction) => {
|
||||
const r = set(state, replace)
|
||||
if (!isRecording) return r
|
||||
const action: { type: unknown } =
|
||||
const action: { type: string } =
|
||||
nameOrAction === undefined
|
||||
? { type: anonymousActionType || 'anonymous' }
|
||||
: typeof nameOrAction === 'string'
|
||||
? { type: nameOrAction }
|
||||
: nameOrAction
|
||||
? { type: nameOrAction }
|
||||
: nameOrAction
|
||||
if (store === undefined) {
|
||||
connection?.send(action, get())
|
||||
return r
|
||||
|
||||
@ -21,16 +21,16 @@ type Write<T, U> = Omit<T, keyof U> & U
|
||||
type SkipTwo<T> = T extends { length: 0 }
|
||||
? []
|
||||
: T extends { length: 1 }
|
||||
? []
|
||||
: T extends { length: 0 | 1 }
|
||||
? []
|
||||
: T extends [unknown, unknown, ...infer A]
|
||||
? A
|
||||
: T extends [unknown, unknown?, ...infer A]
|
||||
? A
|
||||
: T extends [unknown?, unknown?, ...infer A]
|
||||
? A
|
||||
: never
|
||||
? []
|
||||
: T extends { length: 0 | 1 }
|
||||
? []
|
||||
: T extends [unknown, unknown, ...infer A]
|
||||
? A
|
||||
: T extends [unknown, unknown?, ...infer A]
|
||||
? A
|
||||
: T extends [unknown?, unknown?, ...infer A]
|
||||
? A
|
||||
: never
|
||||
|
||||
type WithImmer<S> = Write<S, StoreImmer<S>>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@ import type { NamedSet } from './devtools.ts'
|
||||
|
||||
type Write<T, U> = Omit<T, keyof U> & U
|
||||
|
||||
type Action = { type: unknown }
|
||||
type Action = { type: string }
|
||||
|
||||
type StoreRedux<A> = {
|
||||
dispatch: (a: A) => A
|
||||
|
||||
@ -20,10 +20,10 @@ type Get<T, K, F> = K extends keyof T ? T[K] : F
|
||||
export type Mutate<S, Ms> = number extends Ms['length' & keyof Ms]
|
||||
? S
|
||||
: Ms extends []
|
||||
? S
|
||||
: Ms extends [[infer Mi, infer Ma], ...infer Mrs]
|
||||
? Mutate<StoreMutators<S, Ma>[Mi & StoreMutatorIdentifier], Mrs>
|
||||
: never
|
||||
? S
|
||||
: Ms extends [[infer Mi, infer Ma], ...infer Mrs]
|
||||
? Mutate<StoreMutators<S, Ma>[Mi & StoreMutatorIdentifier], Mrs>
|
||||
: never
|
||||
|
||||
export type StateCreator<
|
||||
T,
|
||||
@ -73,7 +73,7 @@ const createStoreImpl: CreateStoreImpl = (createState) => {
|
||||
if (!Object.is(nextState, state)) {
|
||||
const previousState = state
|
||||
state =
|
||||
replace ?? typeof nextState !== 'object'
|
||||
replace ?? (typeof nextState !== 'object' || nextState === null)
|
||||
? (nextState as TState)
|
||||
: Object.assign({}, state, nextState)
|
||||
listeners.forEach((listener) => listener(state, previousState))
|
||||
|
||||
@ -112,6 +112,24 @@ it('can set the store without merging', () => {
|
||||
expect(getState()).toEqual({ b: 2 })
|
||||
})
|
||||
|
||||
it('can set the object store to null', () => {
|
||||
const { setState, getState } = createStore<{ a: number } | null>(() => ({
|
||||
a: 1,
|
||||
}))
|
||||
|
||||
setState(null)
|
||||
|
||||
expect(getState()).toEqual(null)
|
||||
})
|
||||
|
||||
it('can set the non-object store to null', () => {
|
||||
const { setState, getState } = createStore<string | null>(() => 'value')
|
||||
|
||||
setState(null)
|
||||
|
||||
expect(getState()).toEqual(null)
|
||||
})
|
||||
|
||||
it('works with non-object state', () => {
|
||||
const store = createStore<number>(() => 1)
|
||||
const inc = () => store.setState((c) => c + 1)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user