mirror of
https://github.com/pmndrs/zustand.git
synced 2025-12-08 19:45:52 +00:00
docs(typescript): clean up bounded useStore recipe (#1581)
* Make bounded useStore recipe section minimal * Add a receipe for `createBoundedUseStore` * run prettier * use vanilla store (as the react store is already a bounded useStore hook)
This commit is contained in:
parent
04080fdedc
commit
f508b2c315
@ -399,11 +399,10 @@ A detailed explanation on the slices pattern can be found [here](./slices-patter
|
||||
|
||||
If you have some middlewares then replace `StateCreator<MyState, [], [], MySlice>` with `StateCreator<MyState, Mutators, [], MySlice>`. For example, if you are using `devtools` then it will be `StateCreator<MyState, [["zustand/devtools", never]], [], MySlice>`. See the ["Middlewares and their mutators reference"](#middlewares-and-their-mutators-reference) section for a list of all mutators.
|
||||
|
||||
### Using a vanilla store as a bound store
|
||||
|
||||
Create your vanilla store:
|
||||
### Bounded `useStore` hook for vanilla stores
|
||||
|
||||
```ts
|
||||
import { useStore } from 'zustand'
|
||||
import { createStore } from 'zustand/vanilla'
|
||||
|
||||
interface BearState {
|
||||
@ -411,79 +410,56 @@ interface BearState {
|
||||
increase: (by: number) => void
|
||||
}
|
||||
|
||||
export const initialBearState = { bears: 0 }
|
||||
export const vanillaBearStore = createStore<BearState>((set, getState) => ({
|
||||
...initialBearState,
|
||||
const bearStore = createStore<BearState>()((set) => ({
|
||||
bears: 0,
|
||||
increase: (by) => set((state) => ({ bears: state.bears + by })),
|
||||
}))
|
||||
```
|
||||
|
||||
Create a hook to provide a bound store to be used in your component:
|
||||
|
||||
```ts
|
||||
import { useStore } from 'zustand'
|
||||
|
||||
export function useBoundBearStore(): BearState
|
||||
export function useBoundBearStore<T>(
|
||||
function useBearStore(): BearState
|
||||
function useBearStore<T>(
|
||||
selector: (state: BearState) => T,
|
||||
equals?: (a: T, b: T) => boolean
|
||||
): T
|
||||
export function useBoundBearStore(selector?: any, equals?: any) {
|
||||
return useStore(vanillaBearStore, selector, equals)
|
||||
function useBearStore<T>(
|
||||
selector?: (state: BearState) => T,
|
||||
equals?: (a: T, b: T) => boolean
|
||||
) {
|
||||
return useStore(bearStore, selector!, equals)
|
||||
}
|
||||
```
|
||||
|
||||
> **_NOTE:_** We prefer function overloading here, as this closely follows the definition of `useStore` itself.
|
||||
> If you are not familiar with this pattern, just have a look here: [Typescript Docs](https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads)
|
||||
|
||||
Now you can access your vanilla store (e.g. in your tests) like:
|
||||
|
||||
```ts
|
||||
import { vanillaBearStore, initialBearState } from './BearStore'
|
||||
|
||||
describe('MyComponent should', () => {
|
||||
// remember to reset the store
|
||||
beforeEach(() => {
|
||||
vanillaBearStore.setState(initialBearState)
|
||||
})
|
||||
|
||||
it('set the value', () => {
|
||||
const store = vanillaBearStore
|
||||
// do the test
|
||||
expect(store.getState().bears).toEqual(0)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
And access the store in your component
|
||||
|
||||
```tsx
|
||||
import { useBoundBearStore } from './BearStore'
|
||||
|
||||
export const BearComponent = () => {
|
||||
const bears = useBoundBearStore((state) => state.bears)
|
||||
|
||||
return <div>{bears}</div>
|
||||
}
|
||||
```
|
||||
|
||||
If you want to use middlewares with your store:
|
||||
You can also make an abstract `createBoundedUseStore` if you create bounded `useStore`s often and want to DRY things up...
|
||||
|
||||
```ts
|
||||
import { useStore, StoreApi } from 'zustand'
|
||||
import { createStore } from 'zustand/vanilla'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
|
||||
export const vanillaBearStore = createStore<BearState>()(
|
||||
devtools((set, getState) => ({
|
||||
...initialBearState,
|
||||
increase: (by) => set((state) => ({ bears: state.bears + by })),
|
||||
}))
|
||||
)
|
||||
interface BearState {
|
||||
bears: number
|
||||
increase: (by: number) => void
|
||||
}
|
||||
|
||||
const bearStore = createStore<BearState>()((set) => ({
|
||||
bears: 0,
|
||||
increase: (by) => set((state) => ({ bears: state.bears + by })),
|
||||
}))
|
||||
|
||||
const createBoundedUseStore = ((store) => (selector, equals) =>
|
||||
useStore(store, selector as any, equals)) as <S extends StoreApi<unknown>>(
|
||||
store: S
|
||||
) => {
|
||||
(): ExtractState<S>
|
||||
<T>(
|
||||
selector?: (state: ExtractState<S>) => T,
|
||||
equals?: (a: T, b: T) => boolean
|
||||
): T
|
||||
}
|
||||
|
||||
type ExtractState<S> = S extends { get: () => infer X } ? X : never
|
||||
|
||||
const useBearStore = createBoundedUseStore(bearStore)
|
||||
```
|
||||
|
||||
For more information about why there are extra parentheses,
|
||||
please see the [Basic usage section](#basic-usage).
|
||||
|
||||
## Middlewares and their mutators reference
|
||||
|
||||
- `devtools` — `["zustand/devtools", never]`
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user