mirror of
https://github.com/pmndrs/zustand.git
synced 2025-12-08 19:45:52 +00:00
Add usage with context to docs (#1291)
* docs: context guide proposal * fix(docs): typo & omit comment * fix(docs): remove horizontal rules * fix(docs): add wiki link to DI * fix(docs): format with prettier * fix(docs): cases that model => where... is needed * fix(docs): use sentence case * fix(docs): omit quote block * fix(docs): into "a" custom hook * fix(docs): format with prettier * fix(docs): sort broken nav indexes * Update docs/guides/initialize-state-with-props.md Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com> * fix(docs): reintroduce React.createContext example * scripts: escape quotes * styles: run prettier * fix(docs): omit 'React' from imports * styles: run prettier * styles: run prettier Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com>
This commit is contained in:
parent
eea3944499
commit
4ed81bc11b
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Auto Generating Selectors
|
||||
nav: 7
|
||||
nav: 6
|
||||
---
|
||||
|
||||
We recommend using selectors when using either the properties or actions from the store. You can access values from the store like so:
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Connect to state with URL hash
|
||||
nav: 15
|
||||
nav: 12
|
||||
---
|
||||
|
||||
## State is connected with URL hash
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Calling actions outside a React event handler in pre React 18
|
||||
nav: 11
|
||||
nav: 10
|
||||
---
|
||||
|
||||
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.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Flux inspired practice
|
||||
nav: 6
|
||||
nav: 5
|
||||
---
|
||||
|
||||
Although zustand is an unopinionated library, here are some patterns we recommend:
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: How to reset state
|
||||
nav: 18
|
||||
nav: 13
|
||||
---
|
||||
|
||||
The following pattern can be used to reset the state to its initial value.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Immutable state and merging
|
||||
nav: 5
|
||||
nav: 4
|
||||
---
|
||||
|
||||
Like with React's `useState`, we need to update state immutably.
|
||||
|
||||
143
docs/guides/initialize-state-with-props.md
Normal file
143
docs/guides/initialize-state-with-props.md
Normal file
@ -0,0 +1,143 @@
|
||||
---
|
||||
title: Initialize state with props
|
||||
nav: 14
|
||||
---
|
||||
|
||||
In cases where [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) is needed, such as when a store should be initialized with props from a component, the recommended approach is to use a vanilla store with React.context.
|
||||
|
||||
## Store creator with `createStore`
|
||||
|
||||
```ts
|
||||
import { createStore } from 'zustand'
|
||||
|
||||
interface BearProps {
|
||||
bears: number
|
||||
}
|
||||
|
||||
interface BearState extends BearProps {
|
||||
addBear: () => void
|
||||
}
|
||||
|
||||
type BearStore = ReturnType<typeof createBearStore>
|
||||
|
||||
const createBearStore = (initProps?: Partial<BearProps>) => {
|
||||
const DEFAULT_PROPS: BearProps = {
|
||||
bears: 0,
|
||||
}
|
||||
return createStore<BearState>()((set) => ({
|
||||
...DEFAULT_PROPS,
|
||||
...initProps,
|
||||
addBear: () => set((state) => ({ bears: ++state.bears })),
|
||||
}))
|
||||
}
|
||||
```
|
||||
|
||||
## Creating a context with `React.createContext`
|
||||
|
||||
```ts
|
||||
import { createContext } from 'react'
|
||||
|
||||
export const BearContext = createContext<BearStore | null>(null)
|
||||
```
|
||||
|
||||
## Basic component usage
|
||||
|
||||
```tsx
|
||||
// Provider implementation
|
||||
import { useRef } from 'react'
|
||||
|
||||
function App() {
|
||||
const store = useRef(createBearStore()).current
|
||||
return (
|
||||
<BearContext.Provider value={store}>
|
||||
<BasicConsumer />
|
||||
</BearContext.Provider>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// Consumer component
|
||||
import { useContext } from 'react'
|
||||
import { useStore } from 'zustand'
|
||||
|
||||
function BasicConsumer() {
|
||||
const store = useContext(BearContext)
|
||||
if (!store) throw new Error('Missing BearContext.Provider in the tree')
|
||||
const bears = useStore(store, (s) => s.bears)
|
||||
const addBear = useStore(store, (s) => s.addBear)
|
||||
return (
|
||||
<>
|
||||
<div>{bears} Bears.</div>
|
||||
<button onClick={addBear}>Add bear</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Common patterns
|
||||
|
||||
### Wrapping the context provider
|
||||
|
||||
```tsx
|
||||
// Provider wrapper
|
||||
import { useRef } from 'react'
|
||||
|
||||
type BearProviderProps = React.PropsWithChildren<BearProps>
|
||||
|
||||
function BearProvider({ children, ...props }: BearProviderProps) {
|
||||
const storeRef = useRef<BearStore>()
|
||||
if (!storeRef.current) {
|
||||
storeRef.current = createBearStore(props)
|
||||
}
|
||||
return (
|
||||
<BearContext.Provider value={storeRef.current}>
|
||||
{children}
|
||||
</BearContext.Provider>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Extracting context logic into a custom hook
|
||||
|
||||
```tsx
|
||||
// Mimic the hook returned by `create`
|
||||
import { useContext } from 'react'
|
||||
import { useStore } from 'zustand'
|
||||
|
||||
function useBearContext<T>(
|
||||
selector: (state: BearState) => T,
|
||||
equalityFn?: (left: T, right: T) => boolean
|
||||
): T {
|
||||
const store = useContext(BearContext)
|
||||
if (!store) throw new Error('Missing BearContext.Provider in the tree')
|
||||
return useStore(store, selector, equalityFn)
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// Consumer usage of the custom hook
|
||||
function CommonConsumer() {
|
||||
const bears = useBearContext((s) => s.bears)
|
||||
const addBear = useBearContext((s) => s.addBear)
|
||||
return (
|
||||
<>
|
||||
<div>{bears} Bears.</div>
|
||||
<button onClick={addBear}>Add bear</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Complete example
|
||||
|
||||
```tsx
|
||||
// Provider wrapper & custom hook consumer
|
||||
function App2() {
|
||||
return (
|
||||
<BearProvider bears={2}>
|
||||
<HookConsumer />
|
||||
</BearProvider>
|
||||
)
|
||||
}
|
||||
```
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Map and Set Usage
|
||||
nav: 12
|
||||
nav: 11
|
||||
---
|
||||
|
||||
You need to wrap Maps and Sets inside an object. When you want its update to be reflected (e.g. in React),
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Practice with no store actions
|
||||
nav: 8
|
||||
nav: 7
|
||||
---
|
||||
|
||||
The recommended usage is to colocate actions and states within the store (let your actions be located together with your state).
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Testing
|
||||
description: How to test your new store
|
||||
nav: 10
|
||||
nav: 9
|
||||
---
|
||||
|
||||
## Resetting state between tests in **react-dom**
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: TypeScript Guide
|
||||
nav: 9
|
||||
nav: 8
|
||||
---
|
||||
|
||||
## Basic usage
|
||||
@ -57,7 +57,7 @@ Here again, `x` is `unknown` instead of `string`.
|
||||
|
||||
<details>
|
||||
<summary>More about the inference (just for the people curious and interested in TypeScript)</summary>
|
||||
|
||||
|
||||
In some sense this inference failure is not a problem because a value of type `<T>(f: (t: T) => T) => T` cannot be written. That is to say you can't write the real runtime implementation of `createFoo`. Let's try it:
|
||||
|
||||
```js
|
||||
@ -92,8 +92,8 @@ So we have two problems: lack of inference and unsoundness. Lack of inference ca
|
||||
<summary>Why that currying `()(...)`?</summary>
|
||||
|
||||
<br/>
|
||||
|
||||
**TLDR**: It is a workaround for [microsoft/TypeScript#10571](https://github.com/microsoft/TypeScript/issues/10571).
|
||||
|
||||
**TLDR**: It is a workaround for [microsoft/TypeScript#10571](https://github.com/microsoft/TypeScript/issues/10571).
|
||||
|
||||
Imagine you have a scenario like this:
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Updating nested state object values
|
||||
nav: 4
|
||||
nav: 3
|
||||
---
|
||||
|
||||
## Deeply nested object
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 3rd Party Libraries
|
||||
nav: 14
|
||||
nav: 16
|
||||
---
|
||||
|
||||
Zustand provides bear necessities for state management which is great for most projects; however, some users wish to extend the library's feature set. This can be done using 3rd-party libraries created by the community.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Persist middleware
|
||||
nav: 15
|
||||
nav: 17
|
||||
---
|
||||
|
||||
The persist middleware enables you to store your Zustand state in a storage (e.g. `localStorage`, `AsyncStorage`, `IndexedDB`, etc...) thus persisting it's data.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: v4 Migrations
|
||||
nav: 18
|
||||
nav: 19
|
||||
---
|
||||
|
||||
If you're not using the typed version (either via TypeScript or via JSDoc) then there are no breaking changes for you and hence no migration is needed either.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: createContext from zustand/context
|
||||
nav: 17
|
||||
nav: 18
|
||||
---
|
||||
|
||||
A special `createContext` is provided since v3.5,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Recipes
|
||||
description: How to do all you need with Zustand
|
||||
nav: 13
|
||||
nav: 15
|
||||
---
|
||||
|
||||
⚠️ This doc is still under construction. https://github.com/pmndrs/zustand/discussions/1033
|
||||
|
||||
@ -68,7 +68,7 @@
|
||||
"build:shallow": "rollup -c --config-shallow",
|
||||
"build:context": "rollup -c --config-context",
|
||||
"postbuild": "yarn copy",
|
||||
"prettier": "prettier '*.{js,json,md}' '{examples/src,src,tests,docs}/**/*.{js,jsx,ts,tsx,md,mdx}' --write",
|
||||
"prettier": "prettier \"*.{js,json,md}\" \"{examples/src,src,tests,docs}/**/*.{js,jsx,ts,tsx,md,mdx}\" --write",
|
||||
"prettier:ci": "prettier '*.{js,json,md}' '{examples/src,src,tests,docs}/**/*.{js,jsx,ts,tsx,md,mdx}' --list-different",
|
||||
"eslint": "eslint --fix '*.{js,json}' '{src,tests}/**/*.{ts,tsx}'",
|
||||
"eslint:ci": "eslint '*.{js,json}' '{src,tests}/**/*.{ts,tsx}'",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user