🌙 状态管理之 Zustand 入门和实践
Zustand 是一个轻量级的状态管理库,专为 React 应用设计。它提供了简单且高效的状态管理解决方案,易于上手且功能强大。以下是 Zustand 的入门指南和实践示例。
🌙 1. 安装 Zustand
首先,你需要安装 Zustand:
npm install zustand
1
🌙 2. 创建 Zustand Store
使用 Zustand 创建一个简单的 store。Zustand 使用一个函数来定义 store 的初始状态和操作。
// src/store/useStore.ts
import create from 'zustand';
interface CounterState {
count: number;
increment: () => void;
decrement: () => void;
incrementByAmount: (amount: number) => void;
}
const useStore = create<CounterState>((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
incrementByAmount: (amount) => set((state) => ({ count: state.count + amount })),
}));
export default useStore;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
🌙 3. 使用 Zustand Store
在 React 组件中使用 Zustand store 来访问和更新状态。
// src/components/Counter.tsx
import React from 'react';
import useStore from '../store/useStore';
const Counter = () => {
const count = useStore((state) => state.count);
const increment = useStore((state) => state.increment);
const decrement = useStore((state) => state.decrement);
const incrementByAmount = useStore((state) => state.incrementByAmount);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={() => incrementByAmount(5)}>Increment by 5</button>
</div>
);
};
export default Counter;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
🌙 4. 提供 Store
Zustand 不需要像 Redux 那样提供一个 Provider,因为它直接在组件中使用。因此,你可以直接在应用中使用 Zustand store。
// src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
🌙 5. 实践示例:异步操作
Zustand 支持异步操作,你可以使用 async
函数来处理异步逻辑。
// src/store/useStore.ts
import create from 'zustand';
import { devtools } from 'zustand/middleware';
interface CounterState {
count: number;
status: 'idle' | 'loading' | 'failed';
error: string | null;
increment: () => void;
decrement: () => void;
incrementByAmount: (amount: number) => void;
fetchCount: (amount: number) => void;
}
const useStore = create<CounterState>()(
devtools((set) => ({
count: 0,
status: 'idle',
error: null,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
incrementByAmount: (amount) => set((state) => ({ count: state.count + amount })),
fetchCount: async (amount) => {
set({ status: 'loading', error: null });
try {
const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${amount}`);
const data = await response.json();
set((state) => ({ count: state.count + data.id, status: 'idle' }));
} catch (error) {
set({ status: 'failed', error: (error as Error).message || 'Failed to fetch count' });
}
},
}))
);
export default useStore;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// src/components/Counter.tsx
import React from 'react';
import useStore from '../store/useStore';
const Counter = () => {
const count = useStore((state) => state.count);
const status = useStore((state) => state.status);
const error = useStore((state) => state.error);
const increment = useStore((state) => state.increment);
const decrement = useStore((state) => state.decrement);
const incrementByAmount = useStore((state) => state.incrementByAmount);
const fetchCount = useStore((state) => state.fetchCount);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={() => incrementByAmount(5)}>Increment by 5</button>
<button onClick={() => fetchCount(1)}>
{status === 'loading' ? 'Loading...' : 'Fetch Count'}
</button>
{error && <p>Error: {error}</p>}
</div>
);
};
export default Counter;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
🌙 6. 中间件
Zustand 支持中间件,可以用于日志记录、持久化等。例如,使用 zustand/middleware/devtools
进行调试。
// src/store/useStore.ts
import create from 'zustand';
import { devtools } from 'zustand/middleware';
interface CounterState {
count: number;
status: 'idle' | 'loading' | 'failed';
error: string | null;
increment: () => void;
decrement: () => void;
incrementByAmount: (amount: number) => void;
fetchCount: (amount: number) => void;
}
const useStore = create<CounterState>()(
devtools((set) => ({
count: 0,
status: 'idle',
error: null,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
incrementByAmount: (amount) => set((state) => ({ count: state.count + amount })),
fetchCount: async (amount) => {
set({ status: 'loading', error: null });
try {
const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${amount}`);
const data = await response.json();
set((state) => ({ count: state.count + data.id, status: 'idle' }));
} catch (error) {
set({ status: 'failed', error: (error as Error).message || 'Failed to fetch count' });
}
},
}))
);
export default useStore;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
🌙 7. 类型定义
Zustand 使用 TypeScript 类型系统来确保类型安全。你可以为 store 定义接口,并在组件中使用这些类型。
// src/store/useStore.ts
import create from 'zustand';
import { devtools } from 'zustand/middleware';
interface CounterState {
count: number;
status: 'idle' | 'loading' | 'failed';
error: string | null;
increment: () => void;
decrement: () => void;
incrementByAmount: (amount: number) => void;
fetchCount: (amount: number) => void;
}
const useStore = create<CounterState>()(
devtools((set) => ({
count: 0,
status: 'idle',
error: null,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
incrementByAmount: (amount) => set((state) => ({ count: state.count + amount })),
fetchCount: async (amount) => {
set({ status: 'loading', error: null });
try {
const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${amount}`);
const data = await response.json();
set((state) => ({ count: state.count + data.id, status: 'idle' }));
} catch (error) {
set({ status: 'failed', error: (error as Error).message || 'Failed to fetch count' });
}
},
}))
);
export default useStore;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// src/components/Counter.tsx
import React from 'react';
import useStore from '../store/useStore';
const Counter = () => {
const count = useStore((state) => state.count);
const status = useStore((state) => state.status);
const error = useStore((state) => state.error);
const increment = useStore((state) => state.increment);
const decrement = useStore((state) => state.decrement);
const incrementByAmount = useStore((state) => state.incrementByAmount);
const fetchCount = useStore((state) => state.fetchCount);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={() => incrementByAmount(5)}>Increment by 5</button>
<button onClick={() => fetchCount(1)}>
{status === 'loading' ? 'Loading...' : 'Fetch Count'}
</button>
{error && <p>Error: {error}</p>}
</div>
);
};
export default Counter;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
🌙 总结
通过以上步骤,你可以快速入门并实践 Zustand。Zustand 提供了简单且高效的状态管理解决方案,适用于各种规模的 React 应用。遵循这些最佳实践,可以帮助你编写更健壮、更易维护的代码。