fix(docs): useBoundStore instead of useStore (#1125)

* fix(docs): useBoundStore instead of useStore

* run prettier
This commit is contained in:
Daishi Kato 2022-07-26 08:58:43 +09:00 committed by GitHub
parent f07276c3f5
commit fa581ddd9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 418 additions and 410 deletions

View File

@ -39,7 +39,7 @@ interface BearState {
increment: () => void
}
const useStoreBase = create<BearState>()((set) => ({
const useBearStoreBase = create<BearState>()((set) => ({
bears: 0,
increase: (by) => set((state) => ({ bears: state.bears + by })),
increment: () => set((state) => ({ bears: state.bears + 1 })),
@ -49,17 +49,17 @@ const useStoreBase = create<BearState>()((set) => ({
## Apply that function to your store:
```typescript
const useStore = createSelectors(useStoreBase)
const useBearStore = createSelectors(useBearStoreBase)
```
## Now the selectors are auto generated:
```typescript
// get the property
const bears = useStore.use.bears()
const bears = useBearStore.use.bears()
// get the action
const increase = useStore.use.increment()
const increase = useBearStore.use.increment()
```
## Live Demo

View File

@ -6,14 +6,14 @@ In order to fix this, the action needs to be wrapped in `unstable_batchedUpdates
```jsx
import { unstable_batchedUpdates } from 'react-dom' // or 'react-native'
const useStore = create((set) => ({
const useFishStore = create((set) => ({
fishes: 0,
increaseFishes: () => set((prev) => ({ fishes: prev.fishes + 1 })),
}))
const nonReactCallback = () => {
unstable_batchedUpdates(() => {
useStore.getState().increaseFishes()
useFishStore.getState().increaseFishes()
})
}
```

View File

@ -7,7 +7,7 @@ Although zustand is an unopinionated library, here's one of the recommended usag
- Define dispatch functions at the root level of the store to update one or more store slices
```js
const useStore = create((set) => ({
const useBoundStore = create((set) => ({
storeSliceA: ...,
storeSliceB: ...,
storeSliceC: ...,
@ -34,12 +34,12 @@ const reducer = (state, { type, by = 1 }) => {
}
}
const useStore = create((set) => ({
const useGrumpyStore = create((set) => ({
grumpiness: 0,
dispatch: (args) => set((state) => reducer(state, args)),
}))
const dispatch = useStore((state) => state.dispatch)
const dispatch = useGrumpyStore((state) => state.dispatch)
dispatch({ type: types.increase, by: 2 })
```
@ -48,7 +48,7 @@ Or, just use our redux-middleware. It wires up your main-reducer, sets initial s
```typescript
import { redux } from 'zustand/middleware'
const useStore = create(redux(reducer, initialState))
const useReduxStore = create(redux(reducer, initialState))
```
Another way to update the store could be in functions wrapping the state functions. These could also handle side-effects of actions, for example for HTTP-calls. For using Zustand in a none-reactive way see [the readme](https://github.com/pmndrs/zustand#readingwriting-state-and-reacting-to-changes-outside-of-components)

View File

@ -11,7 +11,7 @@ Quick example:
import create from 'zustand'
import { persist } from 'zustand/middleware'
export const useStore = create(
export const useFishStore = create(
persist(
(set, get) => ({
fishes: 0,
@ -44,7 +44,7 @@ Simply pass a function that returns the storage you want to use.
Example:
```ts
export const useStore = create(
export const useBoundStore = create(
persist(
(set, get) => ({
// ...
@ -78,7 +78,7 @@ Since the only way to store an object in a storage is via a string, you can use
For example, if you want to store your state in base64:
```ts
export const useStore = create(
export const useBoundStore = create(
persist(
(set, get) => ({
// ...
@ -104,7 +104,7 @@ If you pass a custom serialize function, you will most likely need to pass a cus
To continue the example above, you could deserialize the base64 value using the following:
```ts
export const useStore = create(
export const useBoundStore = create(
persist(
(set, get) => ({
// ...
@ -128,7 +128,7 @@ Enables you to omit some of the state's fields to be stored in the storage.
You could omit multiple fields using the following:
```ts
export const useStore = create(
export const useBoundStore = create(
persist(
(set, get) => ({
foo: 0,
@ -148,7 +148,7 @@ export const useStore = create(
Or you could allow only specific fields using the following:
```ts
export const useStore = create(
export const useBoundStore = create(
persist(
(set, get) => ({
foo: 0,
@ -171,7 +171,7 @@ This option enables you to pass a listener function that will be called when the
Example:
```ts
export const useStore = create(
export const useBoundStore = create(
persist(
(set, get) => ({
// ...
@ -218,7 +218,7 @@ The migrate function takes the persisted state and the version number as argumen
For instance, if you want to rename a field, you can use the following:
```ts
export const useStore = create(
export const useBoundStore = create(
persist(
(set, get) => ({
newField: 0, // let's say this field was named otherwise in version 0
@ -275,7 +275,7 @@ The shallow merge will erase the `baz` field from the `foo` object.
One way to fix this would be to give a custom deep merge function:
```ts
export const useStore = create(
export const useBoundStore = create(
persist(
(set, get) => ({
foo: {
@ -307,7 +307,7 @@ This method can you get the options of the middleware.
For example, it can be used to obtain the storage name:
```ts
useStore.persist.getOptions().name
useBoundStore.persist.getOptions().name
```
### `setOptions`
@ -319,7 +319,7 @@ This method enables you to change the middleware options. Note that the new opti
For instance, this can be used to change the storage name:
```ts
useStore.persist.setOptions({
useBoundStore.persist.setOptions({
name: 'new-name',
})
```
@ -327,7 +327,7 @@ useStore.persist.setOptions({
Or even to change the storage engine:
```ts
useStore.persist.setOptions({
useBoundStore.persist.setOptions({
getStorage: () => sessionStorage,
})
```
@ -339,7 +339,7 @@ useStore.persist.setOptions({
This can be used to fully clear the persisted value in the storage.
```ts
useStore.persist.clearStorage()
useBoundStore.persist.clearStorage()
```
### `rehydrate`
@ -350,17 +350,17 @@ In some cases, you might want to trigger a rehydration manually.
This can be done by calling the `rehydrate` method.
```ts
await useStore.persist.rehydrate()
await useBoundStore.persist.rehydrate()
```
### `hasHydrated`
> Schema: `() => boolean`
This is a non-reactive getter to know if the storage has been hydrated (note that this does update when calling `useStore.persist.rehydrate()`).
This is a non-reactive getter to know if the storage has been hydrated (note that this does update when calling `useBoundStore.persist.rehydrate()`).
```ts
useStore.persist.hasHydrated()
useBoundStore.persist.hasHydrated()
```
### `onHydrate`
@ -370,7 +370,7 @@ useStore.persist.hasHydrated()
The given listener will be called when the hydration process starts.
```ts
const unsub = useStore.persist.onHydrate((state) => {
const unsub = useBoundStore.persist.onHydrate((state) => {
console.log('hydration starts')
})
@ -385,7 +385,7 @@ unsub()
The given listener will be called when the hydration process ends.
```ts
const unsub = useStore.persist.onFinishHydration((state) => {
const unsub = useBoundStore.persist.onFinishHydration((state) => {
console.log('hydration finished')
})
@ -420,7 +420,7 @@ There's a fiew different ways to do this.
You can use the `onRehydrateStorage` option to update a field in the store:
```ts
const useStore = create(
const useBoundStore = create(
persist(
(set, get) => ({
// ...
@ -441,7 +441,7 @@ const useStore = create(
);
export default function App() {
const hasHydrated = useStore(state => state._hasHydrated);
const hasHydrated = useBoundStore(state => state._hasHydrated);
if (!hasHydrated) {
return <p>Loading...</p>
@ -456,16 +456,16 @@ export default function App() {
You can also create a custom `useHydration` hook:
```ts
const useStore = create(persist(...))
const useBoundStore = create(persist(...))
const useHydration = () => {
const [hydrated, setHydrated] = useState(useStore.persist.hasHydrated)
const [hydrated, setHydrated] = useState(useBoundStore.persist.hasHydrated)
useEffect(() => {
const unsubHydrate = useStore.persist.onHydrate(() => setHydrated(false)) // Note: this is just in case you want to take into account manual rehydrations. You can remove this if you don't need it/don't want it.
const unsubFinishHydration = useStore.persist.onFinishHydration(() => setHydrated(true))
const unsubHydrate = useBoundStore.persist.onHydrate(() => setHydrated(false)) // Note: this is just in case you want to take into account manual rehydrations. You can remove this if you don't need it/don't want it.
const unsubFinishHydration = useBoundStore.persist.onFinishHydration(() => setHydrated(true))
setHydrated(useStore.persist.hasHydrated())
setHydrated(useBoundStore.persist.hasHydrated())
return () => {
unsubHydrate()
@ -502,7 +502,7 @@ const storage: StateStorage = {
},
}
export const useStore = create(
export const useBoundStore = create(
persist(
(set, get) => ({
fishes: 0,
@ -538,6 +538,6 @@ export const withStorageDOMEvents = (store: StoreWithPersist) => {
}
}
const useStore = create(persist(...))
withStorageDOMEvents(useStore)
const useBoundStore = create(persist(...))
withStorageDOMEvents(useBoundStore)
```

View File

@ -12,7 +12,7 @@ interface BearState {
increase: (by: number) => void
}
const useStore = create<BearState>()((set) => ({
const useBearStore = create<BearState>()((set) => ({
bears: 0,
increase: (by) => set((state) => ({ bears: state.bears + by })),
}))
@ -59,7 +59,7 @@ The thing is Zustand is lying in it's type, the simplest way to prove it by show
```ts
import create from 'zustand/vanilla'
const useStore = create<{ foo: number }>()((_, get) => ({
const useBoundStore = create<{ foo: number }>()((_, get) => ({
foo: get().foo,
}))
```
@ -121,7 +121,7 @@ Alternatively you can also use `combine` which infers the state instead of you h
import create from 'zustand'
import { combine } from 'zustand/middleware'
const useStore = create(
const useBearStore = create(
combine({ bears: 0 }, (set) => ({
increase: (by: number) => set((state) => ({ bears: state.bears + by })),
}))
@ -133,9 +133,9 @@ const useStore = create(
<br/>
We achieve the inference by lying a little in the types of `set`, `get` and `store` that you receive as parameters. The lie is that they're typed in a way as if the state is the first parameter only when in fact the state is the shallow-merge (`{ ...a, ...b }`) of both first parameter and the second parameter's return. So for example `get` from the second parameter has type `() => { bears: number }` and that's a lie as it should be `() => { bears: number, increase: (by: number) => void }`. And `useStore` still has the correct type, ie for example `useStore.getState` is typed as `() => { bears: number, increase: (by: number) => void }`.
We achieve the inference by lying a little in the types of `set`, `get` and `store` that you receive as parameters. The lie is that they're typed in a way as if the state is the first parameter only when in fact the state is the shallow-merge (`{ ...a, ...b }`) of both first parameter and the second parameter's return. So for example `get` from the second parameter has type `() => { bears: number }` and that's a lie as it should be `() => { bears: number, increase: (by: number) => void }`. And `useBoundStore` still has the correct type, ie for example `useBoundStore.getState` is typed as `() => { bears: number, increase: (by: number) => void }`.
It's not a lie lie because `{ bears: number }` is still a subtype `{ bears: number, increase: (by: number) => void }`, so in most cases there won't be a problem. Just you have to be careful while using replace. For eg `set({ bears: 0 }, true)` would compile but will be unsound as it'll delete the `increase` function. (If you set from "outside" ie `useStore.setState({ bears: 0 }, true)` then it won't compile because the "outside" store knows that `increase` is missing.) Another instance where you should be careful you're doing `Object.keys`, `Object.keys(get())` will return `["bears", "increase"]` and not `["bears"]` (the return type of `get` can make you fall for this).
It's not a lie lie because `{ bears: number }` is still a subtype `{ bears: number, increase: (by: number) => void }`, so in most cases there won't be a problem. Just you have to be careful while using replace. For eg `set({ bears: 0 }, true)` would compile but will be unsound as it'll delete the `increase` function. (If you set from "outside" ie `useBoundStore.setState({ bears: 0 }, true)` then it won't compile because the "outside" store knows that `increase` is missing.) Another instance where you should be careful you're doing `Object.keys`, `Object.keys(get())` will return `["bears", "increase"]` and not `["bears"]` (the return type of `get` can make you fall for this).
So `combine` trades-off a little type-safety for the convenience of not having to write a type for state. Hence you should use `combine` accordingly, usually it's not a big deal and it's okay to use it.
@ -156,7 +156,7 @@ interface BearState {
increase: (by: number) => void
}
const useStore = create<BearState>()(
const useBearStore = create<BearState>()(
devtools(
persist((set) => ({
bears: 0,
@ -179,7 +179,7 @@ interface BearState {
increase: (by: number) => void
}
const useStore = create<BearState>()(
const useBearStore = create<BearState>()(
myMiddlewares((set) => ({
bears: 0,
increase: (by) => set((state) => ({ bears: state.bears + by })),
@ -199,8 +199,8 @@ const foo = (f, bar) => (set, get, store) => {
return f(set, get, store)
}
const useStore = create(foo(() => ({ bears: 0 }), 'hello'))
console.log(useStore.foo.toUpperCase())
const useBearStore = create(foo(() => ({ bears: 0 }), 'hello'))
console.log(useBearStore.foo.toUpperCase())
```
Yes, if you didn't know Zustand middlewares do and are allowed to mutate the store. But how could we possibly encode the mutation on the type-level? That is to say how could do we type `foo` so that this code compiles?
@ -251,7 +251,7 @@ type PopArgument<T extends (...a: never[]) => unknown> = T extends (
// ---
const useStore = create<BearState>()(
const useBearStore = create<BearState>()(
logger(
(set) => ({
bears: 0,
@ -317,8 +317,8 @@ type Cast<T, U> = T extends U ? T : U
// ---
const useStore = create(foo(() => ({ bears: 0 }), 'hello'))
console.log(useStore.foo.toUpperCase())
const useBearStore = create(foo(() => ({ bears: 0 }), 'hello'))
console.log(useBearStore.foo.toUpperCase())
```
### `create` without curried workaround
@ -333,7 +333,7 @@ interface BearState {
increase: (by: number) => void
}
const useStore = create<
const useBearStore = create<
BearState,
[
['zustand/persist', BearState],
@ -380,7 +380,7 @@ const createFishSlice: StateCreator<
addFish: () => set((state) => ({ fishes: state.fishes + 1 })),
})
const useStore = create<BearSlice & FishSlice>()((...a) => ({
const useBoundStore = create<BearSlice & FishSlice>()((...a) => ({
...createBearSlice(...a),
...createFishSlice(...a),
}))

View File

@ -27,7 +27,7 @@ Your store is a hook! You can put anything in it: primitives, objects, functions
```jsx
import create from 'zustand'
const useStore = create((set) => ({
const useBearStore = create((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
@ -40,12 +40,12 @@ Use the hook anywhere, no providers needed. Select your state and the component
```jsx
function BearCounter() {
const bears = useStore((state) => state.bears)
const bears = useBearStore((state) => state.bears)
return <h1>{bears} around here ...</h1>
}
function Controls() {
const increasePopulation = useStore((state) => state.increasePopulation)
const increasePopulation = useBearStore((state) => state.increasePopulation)
return <button onClick={increasePopulation}>one up</button>
}
```
@ -72,7 +72,7 @@ function Controls() {
You can, but bear in mind that it will cause the component to update on every state change!
```jsx
const state = useStore()
const state = useBearStore()
```
## Selecting multiple state slices
@ -80,8 +80,8 @@ const state = useStore()
It detects changes with strict-equality (old === new) by default, this is efficient for atomic state picks.
```jsx
const nuts = useStore((state) => state.nuts)
const honey = useStore((state) => state.honey)
const nuts = useBearStore((state) => state.nuts)
const honey = useBearStore((state) => state.honey)
```
If you want to construct a single object with multiple state-picks inside, similar to redux's mapStateToProps, you can tell zustand that you want the object to be diffed shallowly by passing the `shallow` equality function.
@ -90,22 +90,25 @@ If you want to construct a single object with multiple state-picks inside, simil
import shallow from 'zustand/shallow'
// Object pick, re-renders the component when either state.nuts or state.honey change
const { nuts, honey } = useStore(
const { nuts, honey } = useBearStore(
(state) => ({ nuts: state.nuts, honey: state.honey }),
shallow
)
// Array pick, re-renders the component when either state.nuts or state.honey change
const [nuts, honey] = useStore((state) => [state.nuts, state.honey], shallow)
const [nuts, honey] = useBearStore(
(state) => [state.nuts, state.honey],
shallow
)
// Mapped picks, re-renders the component when state.treats changes in order, count or keys
const treats = useStore((state) => Object.keys(state.treats), shallow)
const treats = useBearStore((state) => Object.keys(state.treats), shallow)
```
For more control over re-rendering, you may provide any custom equality function.
```jsx
const treats = useStore(
const treats = useBearStore(
(state) => state.treats,
(oldTreats, newTreats) => compare(oldTreats, newTreats)
)
@ -118,7 +121,7 @@ The `set` function has a second argument, `false` by default. Instead of merging
```jsx
import omit from 'lodash-es/omit'
const useStore = create((set) => ({
const useFishStore = create((set) => ({
salmon: 1,
tuna: 2,
deleteEverything: () => set({}, true), // clears the entire store, actions included
@ -131,7 +134,7 @@ const useStore = create((set) => ({
Just call `set` when you're ready, zustand doesn't care if your actions are async or not.
```jsx
const useStore = create((set) => ({
const useFishStore = create((set) => ({
fishies: {},
fetch: async (pond) => {
const response = await fetch(pond)
@ -145,7 +148,7 @@ const useStore = create((set) => ({
`set` allows fn-updates `set(state => result)`, but you still have access to state outside of it through `get`.
```jsx
const useStore = create((set, get) => ({
const useSoundStore = create((set, get) => ({
sound: "grunt",
action: () => {
const sound = get().sound
@ -159,22 +162,22 @@ const useStore = 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.
```jsx
const useStore = create(() => ({ paw: true, snout: true, fur: true }))
const useDogStore = create(() => ({ paw: true, snout: true, fur: true }))
// Getting non-reactive fresh state
const paw = useStore.getState().paw
const paw = useDogStore.getState().paw
// Listening to all changes, fires synchronously on every change
const unsub1 = useStore.subscribe(console.log)
const unsub1 = useDogStore.subscribe(console.log)
// Updating state, will trigger listeners
useStore.setState({ paw: false })
useDogStore.setState({ paw: false })
// Unsubscribe listeners
unsub1()
// Destroying the store (removing all listeners)
useStore.destroy()
useDogStore.destroy()
// You can of course use the hook as you always would
const Component = () => {
const paw = useStore((state) => state.paw)
const paw = useDogStore((state) => state.paw)
...
```
@ -191,25 +194,25 @@ subscribe(selector, callback, options?: { equalityFn, fireImmediately }): Unsubs
```js
import { subscribeWithSelector } from 'zustand/middleware'
const useStore = create(
const useDogStore = create(
subscribeWithSelector(() => ({ paw: true, snout: true, fur: true }))
)
// Listening to selected changes, in this case when "paw" changes
const unsub2 = useStore.subscribe((state) => state.paw, console.log)
const unsub2 = useDogStore.subscribe((state) => state.paw, console.log)
// Subscribe also exposes the previous value
const unsub3 = useStore.subscribe(
const unsub3 = useDogStore.subscribe(
(state) => state.paw,
(paw, previousPaw) => console.log(paw, previousPaw)
)
// Subscribe also supports an optional equality function
const unsub4 = useStore.subscribe(
const unsub4 = useDogStore.subscribe(
(state) => [state.paw, state.fur],
console.log,
{ equalityFn: shallow }
)
// Subscribe and fire immediately
const unsub5 = useStore.subscribe((state) => state.paw, console.log, {
const unsub5 = useDogStore.subscribe((state) => state.paw, console.log, {
fireImmediately: true,
})
```
@ -231,7 +234,7 @@ You can even consume an existing vanilla store with React:
import create from 'zustand'
import vanillaStore from './vanillaStore'
const useStore = create(vanillaStore)
const useBoundStore = create(vanillaStore)
```
:warning: Note that middlewares that modify `set` or `get` are not applied to `getState` and `setState`.
@ -241,13 +244,13 @@ const useStore = create(vanillaStore)
The subscribe function allows components to bind to a state-portion without forcing re-render on changes. Best combine it with useEffect for automatic unsubscribe on unmount. This can make a [drastic](https://codesandbox.io/s/peaceful-johnson-txtws) performance impact when you are allowed to mutate the view directly.
```jsx
const useStore = create(set => ({ scratches: 0, ... }))
const useScratchStore = create(set => ({ scratches: 0, ... }))
const Component = () => {
// Fetch initial state
const scratchRef = useRef(useStore.getState().scratches)
const scratchRef = useRef(useScratchStore.getState().scratches)
// Connect to the store on mount, disconnect on unmount, catch state-changes in a reference
useEffect(() => useStore.subscribe(
useEffect(() => useScratchStore.subscribe(
state => (scratchRef.current = state.scratches)
), [])
...
@ -260,7 +263,7 @@ Reducing nested structures is tiresome. Have you tried [immer](https://github.co
```jsx
import produce from 'immer'
const useStore = create((set) => ({
const useLushStore = create((set) => ({
lush: { forest: { contains: { a: 'bear' } } },
clearForest: () =>
set(
@ -270,7 +273,7 @@ const useStore = create((set) => ({
),
}))
const clearForest = useStore((state) => state.clearForest)
const clearForest = useLushStore((state) => state.clearForest)
clearForest()
```
@ -293,7 +296,7 @@ const log = (config) => (set, get, api) =>
api
)
const useStore = create(
const useBeeStore = create(
log((set) => ({
bees: false,
setBees: (input) => set({ bees: input }),
@ -309,7 +312,7 @@ You can persist your store's data using any kind of storage.
import create from 'zustand'
import { persist } from 'zustand/middleware'
const useStore = create(
const useFishStore = create(
persist(
(set, get) => ({
fishes: 0,
@ -333,7 +336,7 @@ Immer is available as middleware too.
import create from 'zustand'
import { immer } from 'zustand/middleware/immer'
const useStore = create(
const useBeeStore = create(
immer((set) => ({
bees: 0,
addBees: (by) =>
@ -358,12 +361,12 @@ const reducer = (state, { type, by = 1 }) => {
}
}
const useStore = create((set) => ({
const useGrumpyStore = create((set) => ({
grumpiness: 0,
dispatch: (args) => set((state) => reducer(state, args)),
}))
const dispatch = useStore((state) => state.dispatch)
const dispatch = useGrumpyStore((state) => state.dispatch)
dispatch({ type: types.increase, by: 2 })
```
@ -372,7 +375,7 @@ Or, just use our redux-middleware. It wires up your main-reducer, sets initial s
```jsx
import { redux } from 'zustand/middleware'
const useStore = create(redux(reducer, initialState))
const useGrumpyStore = create(redux(reducer, initialState))
```
## Redux devtools
@ -381,9 +384,9 @@ const useStore = create(redux(reducer, initialState))
import { devtools } from 'zustand/middleware'
// Usage with a plain action store, it will log actions as "setState"
const useStore = create(devtools(store))
const usePlainStore = create(devtools(store))
// Usage with a redux store, it will log full action types
const useStore = create(devtools(redux(reducer, initialState)))
const useReduxStore = create(devtools(redux(reducer, initialState)))
```
devtools takes the store function as its first argument, optionally you can name the store or configure [serialize](https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md#serialize) options with a second argument.
@ -558,7 +561,7 @@ interface BearState {
increase: (by: number) => void
}
const useStore = create<BearState>()(
const useBearStore = create<BearState>()(
devtools(
persist((set) => ({
bears: 0,

View File

@ -43,13 +43,13 @@ type CounterState = {
}
it('uses the store with no args', async () => {
const useStore = create<CounterState>((set) => ({
const useBoundStore = create<CounterState>((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}))
function Counter() {
const { count, inc } = useStore()
const { count, inc } = useBoundStore()
useEffect(inc, [inc])
return <div>count: {count}</div>
}
@ -60,14 +60,14 @@ it('uses the store with no args', async () => {
})
it('uses the store with selectors', async () => {
const useStore = create<CounterState>((set) => ({
const useBoundStore = create<CounterState>((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}))
function Counter() {
const count = useStore((s) => s.count)
const inc = useStore((s) => s.inc)
const count = useBoundStore((s) => s.count)
const inc = useBoundStore((s) => s.inc)
useEffect(inc, [inc])
return <div>count: {count}</div>
}
@ -78,13 +78,13 @@ it('uses the store with selectors', async () => {
})
it('uses the store with a selector and equality checker', async () => {
const useStore = create(() => ({ item: { value: 0 } }))
const { setState } = useStore
const useBoundStore = create(() => ({ item: { value: 0 } }))
const { setState } = useBoundStore
let renderCount = 0
function Component() {
// Prevent re-render if new value === 1.
const item = useStore(
const item = useBoundStore(
(s) => s.item,
(_, newItem) => newItem.value === 1
)
@ -109,7 +109,7 @@ it('uses the store with a selector and equality checker', async () => {
})
it('only re-renders if selected state has changed', async () => {
const useStore = create<CounterState>((set) => ({
const useBoundStore = create<CounterState>((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}))
@ -117,13 +117,13 @@ it('only re-renders if selected state has changed', async () => {
let controlRenderCount = 0
function Counter() {
const count = useStore((state) => state.count)
const count = useBoundStore((state) => state.count)
counterRenderCount++
return <div>count: {count}</div>
}
function Control() {
const inc = useStore((state) => state.inc)
const inc = useBoundStore((state) => state.inc)
controlRenderCount++
return <button onClick={inc}>button</button>
}
@ -144,12 +144,12 @@ it('only re-renders if selected state has changed', async () => {
})
it('re-renders with useLayoutEffect', async () => {
const useStore = create(() => ({ state: false }))
const useBoundStore = create(() => ({ state: false }))
function Component() {
const { state } = useStore()
const { state } = useBoundStore()
useLayoutEffect(() => {
useStore.setState({ state: true })
useBoundStore.setState({ state: true })
}, [])
return <>{`${state}`}</>
}
@ -163,13 +163,13 @@ it('re-renders with useLayoutEffect', async () => {
})
it('can batch updates', async () => {
const useStore = create<CounterState>((set) => ({
const useBoundStore = create<CounterState>((set) => ({
count: 0,
inc: () => set((state) => ({ count: state.count + 1 })),
}))
function Counter() {
const { count, inc } = useStore()
const { count, inc } = useBoundStore()
useEffect(() => {
ReactDOM.unstable_batchedUpdates(() => {
inc()
@ -187,13 +187,13 @@ it('can batch updates', async () => {
it('can update the selector', async () => {
type State = { one: string; two: string }
type Props = { selector: (state: State) => string }
const useStore = create<State>(() => ({
const useBoundStore = create<State>(() => ({
one: 'one',
two: 'two',
}))
function Component({ selector }: Props) {
return <div>{useStore(selector)}</div>
return <div>{useBoundStore(selector)}</div>
}
const { findByText, rerender } = render(<Component selector={(s) => s.one} />)
@ -206,13 +206,13 @@ it('can update the selector', async () => {
it('can update the equality checker', async () => {
type State = { value: number }
type Props = { equalityFn: (a: State, b: State) => boolean }
const useStore = create<State>(() => ({ value: 0 }))
const { setState } = useStore
const useBoundStore = create<State>(() => ({ value: 0 }))
const { setState } = useBoundStore
const selector = (s: State) => s
let renderCount = 0
function Component({ equalityFn }: Props) {
const { value } = useStore(selector, equalityFn)
const { value } = useBoundStore(selector, equalityFn)
return (
<div>
renderCount: {++renderCount}, value: {value}
@ -237,19 +237,19 @@ it('can update the equality checker', async () => {
await findByText('renderCount: 3, value: 0')
})
it('can call useStore with progressively more arguments', async () => {
it('can call useBoundStore with progressively more arguments', async () => {
type State = { value: number }
type Props = {
selector?: (state: State) => number
equalityFn?: (a: number, b: number) => boolean
}
const useStore = create<State>(() => ({ value: 0 }))
const { setState } = useStore
const useBoundStore = create<State>(() => ({ value: 0 }))
const { setState } = useBoundStore
let renderCount = 0
function Component({ selector, equalityFn }: Props) {
const value = useStore(selector as any, equalityFn)
const value = useBoundStore(selector as any, equalityFn)
return (
<div>
renderCount: {++renderCount}, value: {JSON.stringify(value)}
@ -286,8 +286,8 @@ it('can throw an error in selector', async () => {
type State = { value: string | number }
const initialState: State = { value: 'foo' }
const useStore = create<State>(() => initialState)
const { setState } = useStore
const useBoundStore = create<State>(() => initialState)
const { setState } = useBoundStore
const selector = (s: State) =>
// @ts-expect-error This function is supposed to throw an error
s.value.toUpperCase()
@ -309,7 +309,7 @@ it('can throw an error in selector', async () => {
}
function Component() {
useStore(selector)
useBoundStore(selector)
return <div>no error</div>
}
@ -331,8 +331,8 @@ it('can throw an error in equality checker', async () => {
type State = { value: string | number }
const initialState: State = { value: 'foo' }
const useStore = create(() => initialState)
const { setState } = useStore
const useBoundStore = create(() => initialState)
const { setState } = useBoundStore
const selector = (s: State) => s
const equalityFn = (a: State, b: State) =>
// @ts-expect-error This function is supposed to throw an error
@ -355,7 +355,7 @@ it('can throw an error in equality checker', async () => {
}
function Component() {
useStore(selector, equalityFn)
useBoundStore(selector, equalityFn)
return <div>no error</div>
}
@ -439,8 +439,8 @@ it('can destroy the store', () => {
it('only calls selectors when necessary', async () => {
type State = { a: number; b: number }
const useStore = create<State>(() => ({ a: 0, b: 0 }))
const { setState } = useStore
const useBoundStore = create<State>(() => ({ a: 0, b: 0 }))
const { setState } = useBoundStore
let inlineSelectorCallCount = 0
let staticSelectorCallCount = 0
@ -450,8 +450,8 @@ it('only calls selectors when necessary', async () => {
}
function Component() {
useStore((s) => (inlineSelectorCallCount++, s.b))
useStore(staticSelector)
useBoundStore((s) => (inlineSelectorCallCount++, s.b))
useBoundStore(staticSelector)
return (
<>
<div>inline: {inlineSelectorCallCount}</div>
@ -478,13 +478,13 @@ it('ensures parent components subscribe before children', async () => {
children: { [key: string]: { text: string } }
}
type Props = { id: string }
const useStore = create<State>(() => ({
const useBoundStore = create<State>(() => ({
children: {
'1': { text: 'child 1' },
'2': { text: 'child 2' },
},
}))
const api = useStore
const api = useBoundStore
function changeState() {
api.setState({
@ -495,12 +495,12 @@ it('ensures parent components subscribe before children', async () => {
}
function Child({ id }: Props) {
const text = useStore((s) => s.children[id]?.text)
const text = useBoundStore((s) => s.children[id]?.text)
return <div>{text}</div>
}
function Parent() {
const childStates = useStore((s) => s.children)
const childStates = useBoundStore((s) => s.children)
return (
<>
<button onClick={changeState}>change state</button>
@ -520,15 +520,15 @@ it('ensures parent components subscribe before children', async () => {
// https://github.com/pmndrs/zustand/issues/84
it('ensures the correct subscriber is removed on unmount', async () => {
const useStore = create(() => ({ count: 0 }))
const api = useStore
const useBoundStore = create(() => ({ count: 0 }))
const api = useBoundStore
function increment() {
api.setState(({ count }) => ({ count: count + 1 }))
}
function Count() {
const c = useStore((s) => s.count)
const c = useBoundStore((s) => s.count)
return <div>count: {c}</div>
}
@ -561,16 +561,16 @@ it('ensures the correct subscriber is removed on unmount', async () => {
// https://github.com/pmndrs/zustand/issues/86
it('ensures a subscriber is not mistakenly overwritten', async () => {
const useStore = create(() => ({ count: 0 }))
const { setState } = useStore
const useBoundStore = create(() => ({ count: 0 }))
const { setState } = useBoundStore
function Count1() {
const c = useStore((s) => s.count)
const c = useBoundStore((s) => s.count)
return <div>count1: {c}</div>
}
function Count2() {
const c = useStore((s) => s.count)
const c = useBoundStore((s) => s.count)
return <div>count2: {c}</div>
}

View File

@ -16,17 +16,17 @@ type CounterState = {
describe('counter state spec (no middleware)', () => {
it('no middleware', () => {
const useStore = create<CounterState>((set, get) => ({
const useBoundStore = create<CounterState>((set, get) => ({
count: 0,
inc: () => set({ count: get().count + 1 }, false),
}))
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
return <></>
}
TestComponent
@ -43,7 +43,7 @@ describe('counter state spec (single middleware)', () => {
})
it('immer', () => {
const useStore = create<CounterState>()(
const useBoundStore = create<CounterState>()(
immer((set, get) => ({
count: 0,
inc: () =>
@ -53,12 +53,12 @@ describe('counter state spec (single middleware)', () => {
}))
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
return <></>
}
TestComponent
@ -69,7 +69,7 @@ describe('counter state spec (single middleware)', () => {
})
it('redux', () => {
const useStore = create(
const useBoundStore = create(
redux<{ count: number }, { type: 'INC' }>(
(state, action) => {
switch (action.type) {
@ -83,10 +83,10 @@ describe('counter state spec (single middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.dispatch)({ type: 'INC' })
useStore().dispatch({ type: 'INC' })
useStore.dispatch({ type: 'INC' })
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.dispatch)({ type: 'INC' })
useBoundStore().dispatch({ type: 'INC' })
useBoundStore.dispatch({ type: 'INC' })
return <></>
}
TestComponent
@ -98,7 +98,7 @@ describe('counter state spec (single middleware)', () => {
it('devtools', () => {
__DEV__ = false
const useStore = create<CounterState>()(
const useBoundStore = create<CounterState>()(
devtools(
(set, get) => ({
count: 0,
@ -108,13 +108,13 @@ describe('counter state spec (single middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.setState({ count: 0 }, false, 'reset')
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.setState({ count: 0 }, false, 'reset')
return <></>
}
TestComponent
@ -125,20 +125,20 @@ describe('counter state spec (single middleware)', () => {
})
it('subscribeWithSelector', () => {
const useStore = create<CounterState>()(
const useBoundStore = create<CounterState>()(
subscribeWithSelector((set, get) => ({
count: 1,
inc: () => set({ count: get().count + 1 }, false),
}))
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.subscribe(
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
)
@ -152,18 +152,18 @@ describe('counter state spec (single middleware)', () => {
})
it('combine', () => {
const useStore = create(
const useBoundStore = create(
combine({ count: 1 }, (set, get) => ({
inc: () => set({ count: get().count + 1 }, false),
}))
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
return <></>
}
TestComponent
@ -174,7 +174,7 @@ describe('counter state spec (single middleware)', () => {
})
it('persist', () => {
const useStore = create<CounterState>()(
const useBoundStore = create<CounterState>()(
persist(
(set, get) => ({
count: 1,
@ -184,13 +184,13 @@ describe('counter state spec (single middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.persist.hasHydrated()
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.persist.hasHydrated()
return <></>
}
TestComponent
@ -201,7 +201,7 @@ describe('counter state spec (single middleware)', () => {
})
it('persist with partialize', () => {
const useStore = create<CounterState>()(
const useBoundStore = create<CounterState>()(
persist(
(set, get) => ({
count: 1,
@ -211,14 +211,14 @@ describe('counter state spec (single middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.persist.hasHydrated()
useStore.persist.setOptions({
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.persist.hasHydrated()
useBoundStore.persist.setOptions({
// @ts-expect-error to test if the partialized state is inferred as number
partialize: () => 'not-a-number',
})
@ -228,7 +228,7 @@ describe('counter state spec (single middleware)', () => {
})
it('persist without custom api (#638)', () => {
const useStore = create<CounterState>()(
const useBoundStore = create<CounterState>()(
persist(
(set, get) => ({
count: 1,
@ -238,12 +238,12 @@ describe('counter state spec (single middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
return <></>
}
TestComponent
@ -261,7 +261,7 @@ describe('counter state spec (double middleware)', () => {
it('devtools & immer', () => {
__DEV__ = false
const useStore = create<CounterState>()(
const useBoundStore = create<CounterState>()(
devtools(
immer((set, get) => ({
count: 0,
@ -274,13 +274,13 @@ describe('counter state spec (double middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.setState({ count: 0 }, false, 'reset')
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.setState({ count: 0 }, false, 'reset')
return <></>
}
TestComponent
@ -288,7 +288,7 @@ describe('counter state spec (double middleware)', () => {
it('devtools & redux', () => {
__DEV__ = false
const useStore = create(
const useBoundStore = create(
devtools(
redux(
(state, action: { type: 'INC' }) => {
@ -305,11 +305,11 @@ describe('counter state spec (double middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.dispatch)({ type: 'INC' })
useStore().dispatch({ type: 'INC' })
useStore.dispatch({ type: 'INC' })
useStore.setState({ count: 0 }, false, 'reset')
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.dispatch)({ type: 'INC' })
useBoundStore().dispatch({ type: 'INC' })
useBoundStore.dispatch({ type: 'INC' })
useBoundStore.setState({ count: 0 }, false, 'reset')
return <></>
}
TestComponent
@ -317,7 +317,7 @@ describe('counter state spec (double middleware)', () => {
it('devtools & combine', () => {
__DEV__ = false
const useStore = create(
const useBoundStore = create(
devtools(
combine({ count: 1 }, (set, get) => ({
inc: () => set({ count: get().count + 1 }, false, 'inc'),
@ -326,20 +326,20 @@ describe('counter state spec (double middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.setState({ count: 0 }, false, 'reset')
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.setState({ count: 0 }, false, 'reset')
return <></>
}
TestComponent
})
it('subscribeWithSelector & combine', () => {
const useStore = create(
const useBoundStore = create(
subscribeWithSelector(
combine({ count: 1 }, (set, get) => ({
inc: () => set({ count: get().count + 1 }, false),
@ -347,13 +347,13 @@ describe('counter state spec (double middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.subscribe(
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
)
@ -364,7 +364,7 @@ describe('counter state spec (double middleware)', () => {
it('devtools & subscribeWithSelector', () => {
__DEV__ = false
const useStore = create<CounterState>()(
const useBoundStore = create<CounterState>()(
devtools(
subscribeWithSelector((set, get) => ({
count: 1,
@ -374,17 +374,17 @@ describe('counter state spec (double middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.subscribe(
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
)
useStore.setState({ count: 0 }, false, 'reset')
useBoundStore.setState({ count: 0 }, false, 'reset')
return <></>
}
TestComponent
@ -392,7 +392,7 @@ describe('counter state spec (double middleware)', () => {
it('devtools & persist', () => {
__DEV__ = false
const useStore = create<CounterState>()(
const useBoundStore = create<CounterState>()(
devtools(
persist(
(set, get) => ({
@ -405,14 +405,14 @@ describe('counter state spec (double middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.setState({ count: 0 }, false, 'reset')
useStore.persist.hasHydrated()
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.setState({ count: 0 }, false, 'reset')
useBoundStore.persist.hasHydrated()
return <></>
}
TestComponent
@ -430,7 +430,7 @@ describe('counter state spec (triple middleware)', () => {
it('devtools & persist & immer', () => {
__DEV__ = false
const useStore = create<CounterState>()(
const useBoundStore = create<CounterState>()(
devtools(
persist(
immer((set, get) => ({
@ -446,14 +446,14 @@ describe('counter state spec (triple middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.setState({ count: 0 }, false, 'reset')
useStore.persist.hasHydrated()
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.setState({ count: 0 }, false, 'reset')
useBoundStore.persist.hasHydrated()
return <></>
}
TestComponent
@ -461,7 +461,7 @@ describe('counter state spec (triple middleware)', () => {
it('devtools & subscribeWithSelector & combine', () => {
__DEV__ = false
const useStore = create(
const useBoundStore = create(
devtools(
subscribeWithSelector(
combine({ count: 1 }, (set, get) => ({
@ -472,17 +472,17 @@ describe('counter state spec (triple middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.subscribe(
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
)
useStore.setState({ count: 0 }, false, 'reset')
useBoundStore.setState({ count: 0 }, false, 'reset')
return <></>
}
TestComponent
@ -490,7 +490,7 @@ describe('counter state spec (triple middleware)', () => {
it('devtools & subscribeWithSelector & persist', () => {
__DEV__ = false
const useStore = create<CounterState>()(
const useBoundStore = create<CounterState>()(
devtools(
subscribeWithSelector(
persist(
@ -505,18 +505,18 @@ describe('counter state spec (triple middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.subscribe(
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
)
useStore.setState({ count: 0 }, false, 'reset')
useStore.persist.hasHydrated()
useBoundStore.setState({ count: 0 }, false, 'reset')
useBoundStore.persist.hasHydrated()
return <></>
}
TestComponent
@ -534,7 +534,7 @@ describe('counter state spec (quadruple middleware)', () => {
it('devtools & subscribeWithSelector & persist & immer (#616)', () => {
__DEV__ = false
const useStore = create<CounterState>()(
const useBoundStore = create<CounterState>()(
devtools(
subscribeWithSelector(
persist(
@ -552,18 +552,18 @@ describe('counter state spec (quadruple middleware)', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.subscribe(
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
)
useStore.setState({ count: 0 }, false, 'reset')
useStore.persist.hasHydrated()
useBoundStore.setState({ count: 0 }, false, 'reset')
useBoundStore.persist.hasHydrated()
return <></>
}
TestComponent
@ -572,7 +572,7 @@ describe('counter state spec (quadruple middleware)', () => {
describe('more complex state spec with subscribeWithSelector', () => {
it('#619, #632', () => {
const useStore = create(
const useBoundStore = create(
subscribeWithSelector(
persist(
() => ({
@ -583,14 +583,14 @@ describe('more complex state spec with subscribeWithSelector', () => {
)
)
const TestComponent = () => {
useStore((s) => s.foo)
useStore().foo
useStore.getState().foo
useStore.subscribe(
useBoundStore((s) => s.foo)
useBoundStore().foo
useBoundStore.getState().foo
useBoundStore.subscribe(
(state) => state.foo,
(foo) => console.log(foo)
)
useStore.persist.hasHydrated()
useBoundStore.persist.hasHydrated()
return <></>
}
TestComponent
@ -600,7 +600,7 @@ describe('more complex state spec with subscribeWithSelector', () => {
type MyState = {
foo: number | null
}
const useStore = create<MyState>()(
const useBoundStore = create<MyState>()(
subscribeWithSelector(
() =>
({
@ -609,10 +609,10 @@ describe('more complex state spec with subscribeWithSelector', () => {
)
)
const TestComponent = () => {
useStore((s) => s.foo)
useStore().foo
useStore.getState().foo
useStore.subscribe(
useBoundStore((s) => s.foo)
useBoundStore().foo
useBoundStore.getState().foo
useBoundStore.subscribe(
(state) => state.foo,
(foo) => console.log(foo)
)
@ -627,7 +627,7 @@ describe('more complex state spec with subscribeWithSelector', () => {
authenticated: boolean
authenticate: (username: string, password: string) => Promise<void>
}
const useStore = create<MyState>()(
const useBoundStore = create<MyState>()(
persist(
(set) => ({
token: undefined,
@ -640,12 +640,12 @@ describe('more complex state spec with subscribeWithSelector', () => {
)
)
const TestComponent = () => {
useStore((s) => s.authenticated)
useStore((s) => s.authenticate)('u', 'p')
useStore().authenticated
useStore().authenticate('u', 'p')
useStore.getState().authenticated
useStore.getState().authenticate('u', 'p')
useBoundStore((s) => s.authenticated)
useBoundStore((s) => s.authenticate)('u', 'p')
useBoundStore().authenticated
useBoundStore().authenticate('u', 'p')
useBoundStore.getState().authenticated
useBoundStore.getState().authenticate('u', 'p')
return <></>
}
TestComponent
@ -654,7 +654,7 @@ describe('more complex state spec with subscribeWithSelector', () => {
describe('create with explicitly annotated mutators', () => {
it('subscribeWithSelector & persist', () => {
const useStore = create<
const useBoundStore = create<
CounterState,
[
['zustand/subscribeWithSelector', never],
@ -672,18 +672,18 @@ describe('create with explicitly annotated mutators', () => {
)
)
const TestComponent = () => {
useStore((s) => s.count) * 2
useStore((s) => s.inc)()
useStore().count * 2
useStore().inc()
useStore.getState().count * 2
useStore.getState().inc()
useStore.subscribe(
useBoundStore((s) => s.count) * 2
useBoundStore((s) => s.inc)()
useBoundStore().count * 2
useBoundStore().inc()
useBoundStore.getState().count * 2
useBoundStore.getState().inc()
useBoundStore.subscribe(
(state) => state.count,
(count) => console.log(count * 2)
)
useStore.setState({ count: 0 }, false)
useStore.persist.hasHydrated()
useBoundStore.setState({ count: 0 }, false)
useBoundStore.persist.hasHydrated()
return <></>
}
TestComponent

View File

@ -50,7 +50,7 @@ describe('persist middleware with async configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(
() => ({
count: 0,
@ -65,7 +65,7 @@ describe('persist middleware with async configuration', () => {
)
function Counter() {
const { count, name } = useStore()
const { count, name } = useBoundStore()
return (
<div>
count: {count}, name: {name}
@ -94,7 +94,7 @@ describe('persist middleware with async configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
@ -103,7 +103,7 @@ describe('persist middleware with async configuration', () => {
)
function Counter() {
const { count } = useStore()
const { count } = useBoundStore()
return <div>count: {count}</div>
}
@ -123,21 +123,21 @@ describe('persist middleware with async configuration', () => {
const createStore = () => {
const onRehydrateStorageSpy = jest.fn()
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
onRehydrateStorage: () => onRehydrateStorageSpy,
})
)
return { useStore, onRehydrateStorageSpy }
return { useBoundStore, onRehydrateStorageSpy }
}
// Initialize from empty storage
const { useStore, onRehydrateStorageSpy } = createStore()
const { useBoundStore, onRehydrateStorageSpy } = createStore()
function Counter() {
const { count } = useStore()
const { count } = useBoundStore()
return <div>count: {count}</div>
}
@ -148,7 +148,7 @@ describe('persist middleware with async configuration', () => {
})
// Write something to the store
act(() => useStore.setState({ count: 42 }))
act(() => useBoundStore.setState({ count: 42 }))
await findByText('count: 42')
expect(setItemSpy).toBeCalledWith(
'test-storage',
@ -158,11 +158,11 @@ describe('persist middleware with async configuration', () => {
// Create the same store a second time and check if the persisted state
// is loaded correctly
const {
useStore: useStore2,
useBoundStore: useBoundStore2,
onRehydrateStorageSpy: onRehydrateStorageSpy2,
} = createStore()
function Counter2() {
const { count } = useStore2()
const { count } = useBoundStore2()
return <div>count: {count}</div>
}
@ -188,7 +188,7 @@ describe('persist middleware with async configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
version: 13,
@ -199,7 +199,7 @@ describe('persist middleware with async configuration', () => {
)
function Counter() {
const { count } = useStore()
const { count } = useBoundStore()
return <div>count: {count}</div>
}
@ -228,7 +228,7 @@ describe('persist middleware with async configuration', () => {
removeItem: () => {},
}
const useStore = create<{
const useBoundStore = create<{
count: number
name: string
setName: (name: string) => void
@ -249,7 +249,7 @@ describe('persist middleware with async configuration', () => {
)
function Component() {
const { count, setName, name } = useStore()
const { count, setName, name } = useBoundStore()
useEffect(() => {
setName('test')
}, [setName])
@ -266,7 +266,7 @@ describe('persist middleware with async configuration', () => {
await findByText('count: 42')
await findByText('name: test')
expect(useStore.getState()).toEqual(
expect(useBoundStore.getState()).toEqual(
expect.objectContaining({
count: 42,
name: 'test',
@ -287,7 +287,7 @@ describe('persist middleware with async configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
version: 13,
@ -297,7 +297,7 @@ describe('persist middleware with async configuration', () => {
)
function Counter() {
const { count } = useStore()
const { count } = useBoundStore()
return <div>count: {count}</div>
}
@ -324,7 +324,7 @@ describe('persist middleware with async configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
version: 13,
@ -337,7 +337,7 @@ describe('persist middleware with async configuration', () => {
)
function Counter() {
const { count } = useStore()
const { count } = useBoundStore()
return <div>count: {count}</div>
}
@ -367,7 +367,7 @@ describe('persist middleware with async configuration', () => {
const unstorableMethod = () => {}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0, unstorableMethod }), {
name: 'test-storage',
getStorage: () => storage,
@ -376,7 +376,7 @@ describe('persist middleware with async configuration', () => {
)
function Counter() {
const { count } = useStore()
const { count } = useBoundStore()
return <div>count: {count}</div>
}
@ -407,7 +407,7 @@ describe('persist middleware with async configuration', () => {
const unstorableMethod = () => {}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0, actions: { unstorableMethod } }), {
name: 'test-storage',
getStorage: () => storage,
@ -424,14 +424,14 @@ describe('persist middleware with async configuration', () => {
)
function Counter() {
const { count } = useStore()
const { count } = useBoundStore()
return <div>count: {count}</div>
}
const { findByText } = render(<Counter />)
await findByText('count: 1')
expect(useStore.getState()).toEqual({
expect(useBoundStore.getState()).toEqual({
count: 1,
actions: {
unstorableMethod,
@ -451,7 +451,7 @@ describe('persist middleware with async configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
@ -460,14 +460,14 @@ describe('persist middleware with async configuration', () => {
)
function Counter() {
const { count } = useStore()
const { count } = useBoundStore()
return <div>count: {count}</div>
}
const { findByText } = render(<Counter />)
await findByText('count: 1')
expect(useStore.getState()).toEqual({
expect(useBoundStore.getState()).toEqual({
count: 1,
})
})
@ -481,7 +481,7 @@ describe('persist middleware with async configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
@ -489,8 +489,8 @@ describe('persist middleware with async configuration', () => {
)
storage.getItem = async () => storageValue
await useStore.persist.rehydrate()
expect(useStore.getState()).toEqual({
await useBoundStore.persist.rehydrate()
expect(useBoundStore.getState()).toEqual({
count: 1,
})
})
@ -502,17 +502,19 @@ describe('persist middleware with async configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
})
)
expect(useStore.persist.hasHydrated()).toBe(false)
await new Promise((resolve) => useStore.persist.onFinishHydration(resolve))
expect(useStore.persist.hasHydrated()).toBe(true)
expect(useBoundStore.persist.hasHydrated()).toBe(false)
await new Promise((resolve) =>
useBoundStore.persist.onFinishHydration(resolve)
)
expect(useBoundStore.persist.hasHydrated()).toBe(true)
await useStore.persist.rehydrate()
expect(useStore.persist.hasHydrated()).toBe(true)
await useBoundStore.persist.rehydrate()
expect(useBoundStore.persist.hasHydrated()).toBe(true)
})
})

View File

@ -46,7 +46,7 @@ describe('persist middleware with sync configuration', () => {
}
const onRehydrateStorageSpy = jest.fn()
const useStore = create(
const useBoundStore = create(
persist(
() => ({
count: 0,
@ -60,7 +60,10 @@ describe('persist middleware with sync configuration', () => {
)
)
expect(useStore.getState()).toEqual({ count: 42, name: 'test-storage' })
expect(useBoundStore.getState()).toEqual({
count: 42,
name: 'test-storage',
})
expect(onRehydrateStorageSpy).toBeCalledWith(
{ count: 42, name: 'test-storage' },
undefined
@ -93,24 +96,24 @@ describe('persist middleware with sync configuration', () => {
const createStore = () => {
const onRehydrateStorageSpy = jest.fn()
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
onRehydrateStorage: () => onRehydrateStorageSpy,
})
)
return { useStore, onRehydrateStorageSpy }
return { useBoundStore, onRehydrateStorageSpy }
}
// Initialize from empty storage
const { useStore, onRehydrateStorageSpy } = createStore()
expect(useStore.getState()).toEqual({ count: 0 })
const { useBoundStore, onRehydrateStorageSpy } = createStore()
expect(useBoundStore.getState()).toEqual({ count: 0 })
expect(onRehydrateStorageSpy).toBeCalledWith({ count: 0 }, undefined)
// Write something to the store
useStore.setState({ count: 42 })
expect(useStore.getState()).toEqual({ count: 42 })
useBoundStore.setState({ count: 42 })
expect(useBoundStore.getState()).toEqual({ count: 42 })
expect(setItemSpy).toBeCalledWith(
'test-storage',
JSON.stringify({ state: { count: 42 }, version: 0 })
@ -119,10 +122,10 @@ describe('persist middleware with sync configuration', () => {
// Create the same store a second time and check if the persisted state
// is loaded correctly
const {
useStore: useStore2,
useBoundStore: useBoundStore2,
onRehydrateStorageSpy: onRehydrateStorageSpy2,
} = createStore()
expect(useStore2.getState()).toEqual({ count: 42 })
expect(useBoundStore2.getState()).toEqual({ count: 42 })
expect(onRehydrateStorageSpy2).toBeCalledWith({ count: 42 }, undefined)
})
@ -141,7 +144,7 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
version: 13,
@ -151,7 +154,7 @@ describe('persist middleware with sync configuration', () => {
})
)
expect(useStore.getState()).toEqual({ count: 99 })
expect(useBoundStore.getState()).toEqual({ count: 99 })
expect(migrateSpy).toBeCalledWith({ count: 42 }, 12)
expect(setItemSpy).toBeCalledWith(
'test-storage',
@ -176,7 +179,7 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
version: 13,
@ -185,7 +188,7 @@ describe('persist middleware with sync configuration', () => {
})
)
expect(useStore.getState()).toEqual({ count: 0 })
expect(useBoundStore.getState()).toEqual({ count: 0 })
expect(console.error).toHaveBeenCalled()
expect(onRehydrateStorageSpy).toBeCalledWith({ count: 0 }, undefined)
})
@ -203,7 +206,7 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
version: 13,
@ -215,7 +218,7 @@ describe('persist middleware with sync configuration', () => {
})
)
expect(useStore.getState()).toEqual({ count: 0 })
expect(useBoundStore.getState()).toEqual({ count: 0 })
expect(onRehydrateStorageSpy).toBeCalledWith(
undefined,
new Error('migrate error')
@ -237,7 +240,7 @@ describe('persist middleware with sync configuration', () => {
const unstorableMethod = () => {}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0, unstorableMethod }), {
name: 'test-storage',
getStorage: () => storage,
@ -247,7 +250,7 @@ describe('persist middleware with sync configuration', () => {
const expectedState = { count: 1, unstorableMethod }
expect(useStore.getState()).toEqual(expectedState)
expect(useBoundStore.getState()).toEqual(expectedState)
expect(onRehydrateStorageSpy).toBeCalledWith(expectedState, undefined)
})
@ -267,7 +270,7 @@ describe('persist middleware with sync configuration', () => {
const unstorableMethod = () => {}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0, actions: { unstorableMethod } }), {
name: 'test-storage',
getStorage: () => storage,
@ -283,7 +286,7 @@ describe('persist middleware with sync configuration', () => {
})
)
expect(useStore.getState()).toEqual({
expect(useBoundStore.getState()).toEqual({
count: 1,
actions: {
unstorableMethod,
@ -303,7 +306,7 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
@ -311,7 +314,7 @@ describe('persist middleware with sync configuration', () => {
})
)
expect(useStore.getState()).toEqual({
expect(useBoundStore.getState()).toEqual({
count: 1,
})
})
@ -325,7 +328,7 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(
() => ({
object: {
@ -359,7 +362,7 @@ describe('persist middleware with sync configuration', () => {
)
)
useStore.setState({})
useBoundStore.setState({})
expect(setItemSpy).toBeCalledWith(
'test-storage',
JSON.stringify({
@ -388,14 +391,14 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
})
)
expect(useStore.persist.getOptions().name).toBeDefined()
expect(useStore.persist.getOptions().name).toBe('test-storage')
expect(useBoundStore.persist.getOptions().name).toBeDefined()
expect(useBoundStore.persist.getOptions().name).toBe('test-storage')
})
it('can change the options through the api', () => {
@ -407,7 +410,7 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
@ -415,20 +418,20 @@ describe('persist middleware with sync configuration', () => {
})
)
useStore.setState({})
useBoundStore.setState({})
expect(setItemSpy).toBeCalledWith(
'test-storage',
'{"state":{"count":0},"version":0}'
)
useStore.persist.setOptions({
useBoundStore.persist.setOptions({
name: 'test-storage-2',
partialize: (state) =>
Object.fromEntries(
Object.entries(state).filter(([key]) => key !== 'count')
),
})
useStore.setState({})
useBoundStore.setState({})
expect(setItemSpy).toBeCalledWith(
'test-storage-2',
'{"state":{},"version":0}'
@ -444,14 +447,14 @@ describe('persist middleware with sync configuration', () => {
removeItem: removeItemSpy,
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
})
)
useStore.persist.clearStorage()
useBoundStore.persist.clearStorage()
expect(removeItemSpy).toBeCalledWith('test-storage')
})
@ -464,7 +467,7 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
@ -472,8 +475,8 @@ describe('persist middleware with sync configuration', () => {
)
storage.getItem = () => storageValue
useStore.persist.rehydrate()
expect(useStore.getState()).toEqual({
useBoundStore.persist.rehydrate()
expect(useBoundStore.getState()).toEqual({
count: 1,
})
})
@ -485,17 +488,17 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
})
)
expect(useStore.persist.hasHydrated()).toBe(true)
expect(useBoundStore.persist.hasHydrated()).toBe(true)
await useStore.persist.rehydrate()
expect(useStore.persist.hasHydrated()).toBe(true)
await useBoundStore.persist.rehydrate()
expect(useBoundStore.persist.hasHydrated()).toBe(true)
})
it('can wait for rehydration through the api', async () => {
@ -513,23 +516,23 @@ describe('persist middleware with sync configuration', () => {
removeItem: () => {},
}
const useStore = create(
const useBoundStore = create(
persist(() => ({ count: 0 }), {
name: 'test-storage',
getStorage: () => storage,
})
)
const hydrateUnsub1 = useStore.persist.onHydrate(onHydrateSpy1)
useStore.persist.onHydrate(onHydrateSpy2)
const hydrateUnsub1 = useBoundStore.persist.onHydrate(onHydrateSpy1)
useBoundStore.persist.onHydrate(onHydrateSpy2)
const finishHydrationUnsub1 = useStore.persist.onFinishHydration(
const finishHydrationUnsub1 = useBoundStore.persist.onFinishHydration(
onFinishHydrationSpy1
)
useStore.persist.onFinishHydration(onFinishHydrationSpy2)
useBoundStore.persist.onFinishHydration(onFinishHydrationSpy2)
storage.getItem = () => storageValue1
await useStore.persist.rehydrate()
await useBoundStore.persist.rehydrate()
expect(onHydrateSpy1).toBeCalledWith({ count: 0 })
expect(onHydrateSpy2).toBeCalledWith({ count: 0 })
expect(onFinishHydrationSpy1).toBeCalledWith({ count: 1 })
@ -539,7 +542,7 @@ describe('persist middleware with sync configuration', () => {
finishHydrationUnsub1()
storage.getItem = () => storageValue2
await useStore.persist.rehydrate()
await useBoundStore.persist.rehydrate()
expect(onHydrateSpy1).not.toBeCalledTimes(2)
expect(onHydrateSpy2).toBeCalledWith({ count: 1 })
expect(onFinishHydrationSpy1).not.toBeCalledTimes(2)

View File

@ -57,23 +57,23 @@ describe('shallow', () => {
})
describe('types', () => {
it('works with useStore and array selector (#1107)', () => {
const useStore = create(() => ({
it('works with useBoundStore and array selector (#1107)', () => {
const useBoundStore = create(() => ({
villages: [] as { name: string }[],
}))
const Component = () => {
const villages = useStore((state) => state.villages, shallow)
const villages = useBoundStore((state) => state.villages, shallow)
return <>{villages.length}</>
}
expect(Component).toBeDefined()
})
it('works with useStore and string selector (#1107)', () => {
const useStore = create(() => ({
it('works with useBoundStore and string selector (#1107)', () => {
const useBoundStore = create(() => ({
refetchTimestamp: '',
}))
const Component = () => {
const refetchTimestamp = useStore(
const refetchTimestamp = useBoundStore(
(state) => state.refetchTimestamp,
shallow
)

View File

@ -46,7 +46,7 @@ it('can use exposed types', () => {
storeApi.setState({ num: v })
},
}))
const useStore = storeApi
const useBoundStore = storeApi
const stateCreator: StateCreator<ExampleState> = (set, get) => ({
num: 1,
@ -74,7 +74,7 @@ it('can use exposed types', () => {
_destroy: StoreApi<ExampleState>['destroy'],
_equalityFn: (a: ExampleState, b: ExampleState) => boolean,
_stateCreator: StateCreator<ExampleState>,
_useStore: UseBoundStore<StoreApi<ExampleState>>
_useBoundStore: UseBoundStore<StoreApi<ExampleState>>
) {
expect(true).toBeTruthy()
}
@ -91,7 +91,7 @@ it('can use exposed types', () => {
storeApi.destroy,
equalityFn,
stateCreator,
useStore
useBoundStore
)
})