React 状态管理实战:用 Redux Toolkit 把全局状态写短写稳
test12026-10-182 次阅读
为什么还要用 Redux Toolkit
Zustand、Jotai 这类轻量方案适合中小项目,但当状态跨多个业务域、需要可预测的时间旅行调试、或者团队已经有 Redux 习惯时,Redux Toolkit(RTK)仍然是更省心的选择。RTK 用 createSlice 把 action、reducer、初始状态收进一处,用 createAsyncThunk 把异步流程标准化,reducer 内部允许直接"修改"草稿状态(底层用 Immer),比手写 switch-case 干净太多。
定义切片与异步 thunk
下面用一个文章列表的缓存切片举例,覆盖同步 reducer 与异步加载两种场景。
// store/articlesSlice.ts
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
import { fetchArticles } from '../api';
export const loadArticles = createAsyncThunk(
'articles/load',
async (page: number) => {
const data = await fetchArticles(page);
return data; // 返回值会进入 fulfilled 的 action.payload
}
);
interface State {
list: { id: number; title: string }[];
loading: boolean;
page: number;
}
const articlesSlice = createSlice({
name: 'articles',
initialState: { list: [], loading: false, page: 1 } as State,
reducers: {
reset(state) {
state.list = [];
state.page = 1;
},
append(state, action: PayloadAction<{ id: number; title: string }>) {
state.list.push(action.payload);
},
},
extraReducers: (builder) => {
builder
.addCase(loadArticles.pending, (state) => { state.loading = true; })
.addCase(loadArticles.fulfilled, (state, action) => {
state.loading = false;
state.list.push(...action.payload);
state.page += 1;
})
.addCase(loadArticles.rejected, (state) => { state.loading = false; });
},
});
export const { reset, append } = articlesSlice.actions;
export default articlesSlice.reducer;
在组件里读取并避免无谓重渲染
组件用 useSelector 取状态。默认比较是全等,返回新对象或新数组会触发重渲染。多个字段建议用 createSelector 做记忆化,或者只挑最小切片。
// List.tsx
import { useSelector, useDispatch } from 'react-redux';
import { loadArticles, reset } from './store/articlesSlice';
export function ArticleList() {
const dispatch = useDispatch();
// 只取 loading 这一个原始值,变化频率低,不会引起多余渲染
const loading = useSelector((s: RootState) => s.articles.loading);
const list = useSelector((s: RootState) => s.articles.list);
return (
<div>
<button onClick={() => dispatch(loadArticles(1))}>加载</button>
{loading && <span>加载中...</span>}
<ul>{list.map((it) => <li key={it.id}>{it.title}</li>)}</ul>
</div>
);
}
几个落地经验
- 把异步 thunk 放在 slice 文件外或单独文件,保持 reducer 纯粹、可测试。
- 列表类数据优先用实体适配器 createEntityAdapter,自带 selectById、selectAll 等记忆化选择器。
- 调试时开 Redux DevTools,时间旅行能直接回放 thunk 的 pending/fulfilled/rejected 全过程。
- 能用局部状态解决的就不要进全局 store,Redux 适合放真正跨页面共享的数据。
T
test1
文章作者
为什么还要用 Redux Toolkit Zustand、Jotai 这类轻量方案适合中小项目,但当状态跨多个业务域、...
- 分类
- 技术
- 发布时间
- 2026-10-18
- 字数
- 约 2572 字
- 阅读
- 2 次
