mirror of
https://github.com/pmndrs/zustand.git
synced 2025-12-08 19:45:52 +00:00
Issue 1120 docs (#1231)
* docs: testing documentation review * docs: auto-generated-selectors documentation review * docs: auto-generated-selectors documentation review * docs: flux-inspired-practices documentation review * docs: flux-inspired-practices documentation review * docs: flux-inspired-practices documentation review * docs: immutable-state-and-merging documentation review * docs: immutable-state-and-merging documentation review * docs: event-handler-in-pre-react-18 documentation review * docs: ran the yarn run prettier command * Update docs/guides/flux-inspired-practice.md Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com>
This commit is contained in:
parent
a413f4a340
commit
daf52ed305
@ -3,13 +3,13 @@ title: Auto Generating Selectors
|
||||
nav: 7
|
||||
---
|
||||
|
||||
It is recommended to use selectors when using either the properties or actions from the store.
|
||||
We recommend using selectors when using either the properties or actions from the store. You can access values from the store like so:
|
||||
|
||||
```typescript
|
||||
const bears = useBearStore((state) => state.bears)
|
||||
```
|
||||
|
||||
However, writing these could be tedious, but you can auto-generate them
|
||||
However, writing these could be tedious. If that is the case for you, you can auto-generate your selectors.
|
||||
|
||||
## create the following function: `createSelectors`
|
||||
|
||||
@ -33,7 +33,7 @@ const createSelectors = <S extends UseBoundStore<StoreApi<State>>>(
|
||||
}
|
||||
```
|
||||
|
||||
## If you have a store like this:
|
||||
If you have a store like this:
|
||||
|
||||
```typescript
|
||||
interface BearState {
|
||||
@ -49,13 +49,13 @@ const useBearStoreBase = create<BearState>()((set) => ({
|
||||
}))
|
||||
```
|
||||
|
||||
## Apply that function to your store:
|
||||
Apply that function to your store:
|
||||
|
||||
```typescript
|
||||
const useBearStore = createSelectors(useBearStoreBase)
|
||||
```
|
||||
|
||||
## Now the selectors are auto generated:
|
||||
Now the selectors are auto generated and you can access them directly:
|
||||
|
||||
```typescript
|
||||
// get the property
|
||||
@ -67,7 +67,7 @@ const increase = useBearStore.use.increment()
|
||||
|
||||
## Live Demo
|
||||
|
||||
for a working example of this, see the [Code Sandbox](https://codesandbox.io/s/zustand-auto-generate-selectors-9i0ob3?file=/src/store.ts:396-408)
|
||||
For a working example of this, see the [Code Sandbox](https://codesandbox.io/s/zustand-auto-generate-selectors-9i0ob3?file=/src/store.ts:396-408).
|
||||
|
||||
## 3rd-party Libraries
|
||||
|
||||
|
||||
@ -3,8 +3,8 @@ title: Calling actions outside a React event handler in pre React 18
|
||||
nav: 11
|
||||
---
|
||||
|
||||
Because React handles `setState` synchronously if it's called outside an event handler. Updating the state outside an event handler will force react to update the components synchronously, therefore adding the risk of encountering the zombie-child effect.
|
||||
In order to fix this, the action needs to be wrapped in `unstable_batchedUpdates`
|
||||
Because React handles `setState` synchronously if it's called outside an event handler, updating the state outside an event handler will force react to update the components synchronously. Therefore, there is a risk of encountering the zombie-child effect.
|
||||
In order to fix this, the action needs to be wrapped in `unstable_batchedUpdates` like so:
|
||||
|
||||
```jsx
|
||||
import { unstable_batchedUpdates } from 'react-dom' // or 'react-native'
|
||||
|
||||
@ -3,11 +3,11 @@ title: Flux inspired practice
|
||||
nav: 6
|
||||
---
|
||||
|
||||
Although zustand is an unopinionated library, here's one of the recommended usages:
|
||||
Although zustand is an unopinionated library, here are some patterns we recommend:
|
||||
|
||||
- Create one single store
|
||||
- Define a store only with `set`
|
||||
- Define dispatch functions at the root level of the store to update one or more store slices
|
||||
- Create a single store;
|
||||
- Always use `set` to define a store;
|
||||
- Define your dispatch functions at the root level of the store to update one or more store slices.
|
||||
|
||||
```js
|
||||
const useBoundStore = create((set) => ({
|
||||
@ -19,11 +19,11 @@ const useBoundStore = create((set) => ({
|
||||
}))
|
||||
```
|
||||
|
||||
See [Splitting the store into separate slices](https://github.com/pmndrs/zustand/blob/main/docs/typescript.md#slices-pattern) for how to define a store with separate slices.
|
||||
See [Splitting the store into separate slices](./typescript.md#slices-pattern) for how to define a store with separate slices.
|
||||
|
||||
## Flux like patterns / "Dispatching" actions
|
||||
## Flux like patterns / "dispatching" actions
|
||||
|
||||
If you can't live without redux-like reducers, you can define a `dispatch` function on the root level of the store like store
|
||||
If you can't live without redux-like reducers, you can define a `dispatch` function on the root level of the store like so:
|
||||
|
||||
```typescript
|
||||
const types = { increase: 'INCREASE', decrease: 'DECREASE' }
|
||||
@ -46,7 +46,7 @@ const dispatch = useGrumpyStore((state) => state.dispatch)
|
||||
dispatch({ type: types.increase, by: 2 })
|
||||
```
|
||||
|
||||
Or, just use our redux-middleware. It wires up your main-reducer, sets initial state, and adds a dispatch function to the state itself and the vanilla api. Try [this](https://codesandbox.io/s/amazing-kepler-swxol) example.
|
||||
You could also use our redux-middleware. It wires up your main reducer, sets initial state, and adds a dispatch function to the state itself and the vanilla api. Check [this example](https://codesandbox.io/s/amazing-kepler-swxol).
|
||||
|
||||
```typescript
|
||||
import { redux } from 'zustand/middleware'
|
||||
@ -54,4 +54,4 @@ import { redux } from 'zustand/middleware'
|
||||
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)
|
||||
Another way to update the store could be through functions wrapping the state functions. These could also handle side-effects of actions. For example, with HTTP-calls. To use Zustand in a none-reactive way, see [the readme](https://github.com/pmndrs/zustand#readingwriting-state-and-reacting-to-changes-outside-of-components).
|
||||
|
||||
@ -3,9 +3,9 @@ title: Immutable state and merging
|
||||
nav: 5
|
||||
---
|
||||
|
||||
Like `useState`, we need to update state immutably.
|
||||
Like with React's `useState`, we need to update state immutably.
|
||||
|
||||
Here's a typical example.
|
||||
Here's a typical example:
|
||||
|
||||
```jsx
|
||||
import create from 'zustand'
|
||||
@ -16,15 +16,15 @@ const useCountStore = create((set) => ({
|
||||
}))
|
||||
```
|
||||
|
||||
The `set` function is to update state in store.
|
||||
Because the state is immutable, it should have been this:
|
||||
The `set` function is to update state in the store.
|
||||
Because the state is immutable, it should have been like this:
|
||||
|
||||
```js
|
||||
set((state) => ({ ...state, count: state.count + 1 }))
|
||||
```
|
||||
|
||||
As this happens very often, `set` actually merges state, and
|
||||
we can skip `...state` part:
|
||||
However, as this is a common pattern, `set` actually merges state, and
|
||||
we can skip the `...state` part:
|
||||
|
||||
```js
|
||||
set((state) => ({ count: state.count + 1 }))
|
||||
@ -32,8 +32,8 @@ set((state) => ({ count: state.count + 1 }))
|
||||
|
||||
## Nested objects
|
||||
|
||||
The `set` function merges state only one level.
|
||||
If you have a nested object, you need to merge them explicitly.
|
||||
The `set` function merges state at only one level.
|
||||
If you have a nested object, you need to merge them explicitly. You will use the spread operator pattern like so:
|
||||
|
||||
```jsx
|
||||
import create from 'zustand'
|
||||
@ -47,12 +47,12 @@ const useCountStore = create((set) => ({
|
||||
}))
|
||||
```
|
||||
|
||||
For complex use cases, consider using some libraries that helps immutable updates.
|
||||
Refer [Updating nested state object values](./updating-nested-state-object-values.md).
|
||||
For complex use cases, consider using some libraries that help with immutable updates.
|
||||
You can refer to [Updating nested state object values](./updating-nested-state-object-values.md).
|
||||
|
||||
## Replace flag
|
||||
|
||||
To disable the merging behavior, you can specify `replace` boolean value to `set`.
|
||||
To disable the merging behavior, you can specify a `replace` boolean value for `set` like so:
|
||||
|
||||
```js
|
||||
set((state) => newState, true)
|
||||
|
||||
@ -8,7 +8,7 @@ nav: 10
|
||||
|
||||
When running tests, the stores are not automatically reset before each test run.
|
||||
|
||||
Thus, there can be cases where the state of one test can affect another. To make sure all tests run with a pristine store state, you can mock `zustand` during testing and replace it with the following code:
|
||||
Thus, there can be cases where the state of one test can affect another. To make sure all tests run with a pristine store state, you can mock `zustand` during testing and use the following code to create your store:
|
||||
|
||||
```jsx
|
||||
import actualCreate from 'zustand'
|
||||
@ -34,13 +34,13 @@ beforeEach(() => {
|
||||
export default create
|
||||
```
|
||||
|
||||
The way you can mock a dependency depends on your test runner.
|
||||
The way you mock a dependency depends on your test runner/library.
|
||||
|
||||
In [jest](https://jestjs.io/), you can create a `__mocks__/zustand.js` and place the code there. If your app is using `zustand/vanilla` instead of `zustand`, then you'll have to place the above code in `__mocks__/zustand/vanilla.js`.
|
||||
In [jest](https://jestjs.io/), you can create a `__mocks__/zustand.js` and place the code in that file. If your app is using `zustand/vanilla` instead of `zustand`, then you'll have to place the above code in `__mocks__/zustand/vanilla.js`.
|
||||
|
||||
## Resetting state between tests in **react-native** and **jest**
|
||||
|
||||
in the `__mocks__/zustand.js` (the `__mocks__` directory should be adjacent to node_modules, unless you configured roots to point to a folder other than the project root [jest docs: mocking node modules](https://jestjs.io/docs/manual-mocks#mocking-node-modules)):
|
||||
You should use the following code in the `__mocks__/zustand.js` file (the `__mocks__` directory should be adjacent to node_modules, placed in the same folder as node_modules, unless you configured roots to point to a folder other than the project root [jest docs: mocking node modules](https://jestjs.io/docs/manual-mocks#mocking-node-modules)):
|
||||
|
||||
```js
|
||||
import { act } from '@testing-library/react-native'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user