中文音译: "su s dan t"
一个小型、快速且可扩展的 bearbones 状态管理解决方案。 Zustand 有一个基于钩子的舒适 API。它不是样板式的或固执己见的,但有足够的约定来明确和类似通量。
不要忽视它,因为它很可爱,它有爪子!我们花了很多时间来处理常见的陷阱,比如可怕的僵尸子问题、React 并发以及混合渲染器之间的上下文丢失。它可能是 React 空间中的唯一状态管理器,可以正确处理所有这些问题。
API
usage
原生环境
- 使用
createStore创建store 对象 - 使用
useStore创建在react 中可以使用hooks
import { useStore } from 'zustand';
import { createStore } from 'zustand/vanilla';
interface IState {
bears: number;
increase: (by: number) => void;
}
const vanillaStore = createStore<IState>((set) => ({
bears: 0,
increase: (by) => set((state) => ({ bears: state.bears + by })),
}));
const useStoreHook = () => useStore(vanillaStore);
export default function VanillaStoreDemo() {
const state = useStoreHook();
return (
<section>
<button
onClick={() => {
state.increase(1);
}}
>
click
</button>
<div>{state.bears}</div>
</section>
);
}
react环境
- 调用
create创建 hooksuseStore - 直接在react环境中使用
import { create } from 'zustand';
const useStore = create<{ counter: number; inc: any }>((set) => ({
counter: 1,
inc: () => set((pre) => ({ ...pre, counter: pre.counter + 1 })),
}));
export default function ZustandDemo() {
const store = useStore((state) => state);
return (
<section>
<button
onClick={() => {
store.inc();
}}
>
click
</button>
<div>{store.counter}</div>
</section>
);
}
结合中间件
类redux的调用
import { create } from 'zustand';
import { redux } from 'zustand/middleware';
const types = { increase: 'INCREASE', decrease: 'DECREASE' };
const reducer = (state: any, { type, by = 1 }: any) => {
switch (type) {
case types.increase:
return { grumpiness: state.grumpiness + by };
case types.decrease:
return { grumpiness: state.grumpiness - by };
default: {
return state;
}
}
};
const useReduxStore = create(redux(reducer, { grumpiness: 0 }));
export default function MiddlewareRedux() {
const { dispatch, ...state } = useReduxStore();
return (
<section>
<button
onClick={() => {
dispatch({ type: types.increase });
}}
>
increase
</button>
<button
onClick={() => {
dispatch({ type: types.decrease });
}}
>
decrease
</button>
<div>{state.grumpiness}</div>
</section>
);
}
结合immer
// 当produce中传入一个函数的时候,会返回一个函数用来接受baseState
import produce from 'immer'
const immerUpdater = produce((draft) => {
if (draft.value > 3) {
draft.status = '↑';
// return { name: '↑' };
} else if (draft.value === 3) {
draft.status = '--';
// return { name: '--' };
} else {
// 会被重置为一个新的状态
return { name: '↓' };
}
});
console.log(immerUpdater({ value: 5 })); // {value: 5, status: '↑'}
console.log(immerUpdater({ value: 3 })); // {value: 3, status: '--'}
console.log(immerUpdater({ value: 1 })); // {name: '↓'}
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
interface Todo {
id: string;
title: string;
done: boolean;
}
type State = {
todos: Array<Todo>;
};
type Actions = {
toggleTodo: (todoId: string) => void;
};
export const useTodoStore = create(
immer<State & Actions>((set) => ({
todos: [
{
id: '82471c5f-4207-4b1d-abcb-b98547e01a3e',
title: 'Learn Zustand',
done: false,
},
{
id: '354ee16c-bfdd-44d3-afa9-e93679bda367',
title: 'Learn Jotai',
done: false,
},
{
id: '771c85c5-46ea-4a11-8fed-36cc2c7be344',
title: 'Learn Valtio',
done: false,
},
{
id: '363a4bac-083f-47f7-a0a2-aeeee153a99c',
title: 'Learn Signals',
done: false,
},
],
toggleTodo: (todoId: string) => {
set((state) => {
const todo = state.todos.find((d) => d.id === todoId);
if (todo) {
todo.done = !todo.done;
}
});
},
})),
);
export default function MiddlewareImmer() {
const { todos, toggleTodo } = useTodoStore();
return (
<section>
<ul>
{todos.map((todo) => {
return (
<li
key={todo.id}
style={{
textDecorationLine: todo.done ? 'line-through' : 'none',
width: 200,
display: 'flex',
justifyContent: 'space-between',
marginTop: 10,
}}
>
<span>{todo.title}</span>
<button onClick={() => toggleTodo(todo.id)}>toggle</button>
</li>
);
})}
</ul>
</section>
);
}