文章目录
-
-
- 第一阶段:定义数据切片
- [第二阶段:配置全局 Store](#第二阶段:配置全局 Store)
- 第三阶段:组件使用
- 极简代码模板
-
- [1. Slice (userSlice.ts)](#1. Slice (userSlice.ts))
- [2. Store (store.ts)](#2. Store (store.ts))
- [3. Component (Page.tsx)](#3. Component (Page.tsx))
-
Redux 的三个核心阶段( 定义 Slice -> 配置 Store -> 组件使用 )
第一阶段:定义数据切片
这一步是业务逻辑的核心。
- 1. 定义
IState: 为了类型安全,必须定义。 - 2.
initialState: - 3.
createAsyncThunk: 专门处理 HTTP 请求。 - 4.
createSlice: - 5.
reducersvsextraReducers:- 补充 :
reducers处理同步(如:toggleMenu),extraReducers监听异步 Thunk 的状态(pending,fulfilled,rejected)。 - 注意 :在 TS 中,
extraReducers现在推荐使用 builder callback 写法(builder.addCase(...)),这样类型推断最准确。
- 补充 :
- 6. Export : 导出
actions给 UI 用,导出reducer给 Store 用。
第二阶段:配置全局 Store
这一步是把分散的 Slice 组装成大脑。
- 7.
combineReducers:- 这一步在 RTK 中是可选 的。直接传一个对象,
configureStore底层会自动帮你调combineReducers。 - 写法 :
const rootReducer = combineReducers({ user, order }) - 简化写法 :
reducer: { user: userReducer, order: orderReducer }(推荐,少写一行代码)。
- 这一步在 RTK 中是可选 的。直接传一个对象,
- 8.
configureStore: 这是 RTK 的核心,自动开启了 Redux DevTools。 - 9. Export Hooks : 非常重要!
- 你提到了
useAppDispatch和useAppSelector,这非常关键。 - 原因 :原生的
useDispatch不知道你 Thunk 的类型,原生的useSelector不知道你RootState的结构。二次封装后,你在组件里写代码会有完美的 TS 提示。
- 你提到了
第三阶段:组件使用
这一步是 UI 与数据交互。
- 10.
useAppDispatch:- 术语纠正 :我们通过 dispatch 触发 action,而不是直接调用 reducers。Reducers 是在后台听到 action 后执行的。
- **11.
useAppSelector:- 补充:它会自动订阅更新。只要 Store 里的数据变了,组件会自动 Re-render(重新渲染),不需要你手动干预。
- 12.
useEffect监听 :- 场景 A(自动更新视图) :不需要
useEffect。useAppSelector拿到的数据变了,页面这块 DOM 自动就变了。 - 场景 B(副作用) :比如"登录成功后跳转页面"或者"弹出成功提示",这种才需要用
useEffect监听状态变化。
- 场景 A(自动更新视图) :不需要
极简代码模板
1. Slice (userSlice.ts)
typescript
// Step 1
interface UserState {
loading: boolean;
data: any;
}
// Step 2
const initialState: UserState = { loading: false, data: null };
// Step 3
export const loginUser = createAsyncThunk('user/login', async (params) => {
return await api.login(params);
});
// Step 4
const userSlice = createSlice({
name: 'user',
initialState,
// Step 5: 同步
reducers: {
logout: (state) => { state.data = null; }
},
// Step 5: 异步 (Builder 写法是 TS 最佳实践)
extraReducers: (builder) => {
builder.addCase(loginUser.fulfilled, (state, action) => {
state.data = action.payload;
});
}
});
// Step 6
export const { logout } = userSlice.actions;
export default userSlice.reducer;
2. Store (store.ts)
typescript
import { configureStore } from '@reduxjs/toolkit';
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import userReducer from './userSlice';
// Step 7 & 8 (合并写法)
export const store = configureStore({
reducer: {
user: userReducer, // 这里自动 combineReducers
},
});
// Step 9: 导出 TS 类型和 Hooks
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
3. Component (Page.tsx)
typescript
// Step 10
const dispatch = useAppDispatch();
// Step 11
const { data, loading } = useAppSelector(state => state.user);
// 触发操作
const handleLogin = () => {
dispatch(loginUser({ username: 'admin' }));
};
// Step 12 (仅用于副作用)
useEffect(() => {
if (data) {
message.success('登录成功');
}
}, [data]);