个人笔记
1. 基础概念
1.1 什么是 Redux
Redux 是一个用于 JavaScript 应用的状态管理工具,它帮助你以可预测的方式管理应用状态。
1.2 核心概念
- Store: 保存数据的地方,整个应用只能有一个 Store
- Action: 描述发生了什么的普通对象
- Reducer: 描述如何更新状态的纯函数
- Dispatch: 发送 action 的方法
2. 基本使用
2.1 安装依赖
npm install redux react-redux @reduxjs/toolkit
2.2 创建 Store
// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';
export const store = configureStore({
reducer: {
counter: counterReducer,
},
});
2.3 创建 Slice
// store/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0,
},
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
},
incrementByAmount: (state, action) => {
state.value += action.payload;
},
},
});
export const { increment, decrement, incrementByAmount } = counterSlice.actions;
export default counterSlice.reducer;
2.4 Provider 配置
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { store } from './store';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
3. 在组件中使用
3.1 使用 Hooks
// components/Counter.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, incrementByAmount } from '../store/counterSlice';
function Counter() {
// 获取状态
const count = useSelector((state) => state.counter.value);
// 获取 dispatch 方法
const dispatch = useDispatch();
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => dispatch(increment())}>
Increment
</button>
<button onClick={() => dispatch(decrement())}>
Decrement
</button>
<button onClick={() => dispatch(incrementByAmount(5))}>
Add 5
</button>
</div>
);
}
export default Counter;
3.2 异步操作
// store/counterSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
// 创建异步 action
export const fetchCount = createAsyncThunk(
'counter/fetchCount',
async (amount) => {
const response = await fetch(`/api/counter?amount=${amount}`);
const data = await response.json();
return data.value;
}
);
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0,
status: 'idle',
error: null,
},
reducers: {
// ... 同步 reducers
},
extraReducers: (builder) => {
builder
.addCase(fetchCount.pending, (state) => {
state.status = 'loading';
})
.addCase(fetchCount.fulfilled, (state, action) => {
state.status = 'succeeded';
state.value += action.payload;
})
.addCase(fetchCount.rejected, (state, action) => {
state.status = 'failed';
state.error = action.error.message;
});
},
});
3.3 在组件中使用异步操作
// components/AsyncCounter.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchCount } from '../store/counterSlice';
function AsyncCounter() {
const count = useSelector((state) => state.counter.value);
const status = useSelector((state) => state.counter.status);
const error = useSelector((state) => state.counter.error);
const dispatch = useDispatch();
return (
<div>
<h2>Async Count: {count}</h2>
<div>Status: {status}</div>
{error && <div>Error: {error}</div>}
<button
onClick={() => dispatch(fetchCount(1))}
disabled={status === 'loading'}
>
Fetch Count
</button>
</div>
);
}
export default AsyncCounter;
4. 高级用法
4.1 中间件使用
// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import logger from 'redux-logger';
import counterReducer from './counterSlice';
export const store = configureStore({
reducer: {
counter: counterReducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(logger),
});
4.2 多个 Reducer 的组合
// store/userSlice.js
import { createSlice } from '@reduxjs/toolkit';
const userSlice = createSlice({
name: 'user',
initialState: {
currentUser: null,
loading: false,
},
reducers: {
setUser: (state, action) => {
state.currentUser = action.payload;
},
clearUser: (state) => {
state.currentUser = null;
},
},
});
export const { setUser, clearUser } = userSlice.actions;
export default userSlice.reducer;
// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';
import userReducer from './userSlice';
export const store = configureStore({
reducer: {
counter: counterReducer,
user: userReducer,
},
});
4.3 Selector 优化
// store/selectors.js
import { createSelector } from '@reduxjs/toolkit';
// 基础 selector
const selectCounter = state => state.counter;
const selectUser = state => state.user;
// 复杂 selector
export const selectCounterValue = createSelector(
[selectCounter],
counter => counter.value
);
export const selectUserWithCount = createSelector(
[selectUser, selectCounter],
(user, counter) => ({
user: user.currentUser,
count: counter.value,
})
);
// 在组件中使用
function UserCounter() {
const { user, count } = useSelector(selectUserWithCount);
return (
<div>
<h3>User: {user?.name}</h3>
<p>Count: {count}</p>
</div>
);
}
5. 最佳实践
5.1 Action 类型常量
// store/types.js
export const COUNTER_TYPES = {
INCREMENT: 'counter/increment',
DECREMENT: 'counter/decrement',
INCREMENT_BY_AMOUNT: 'counter/incrementByAmount',
};
5.2 Action 创建器
// store/actions.js
import { COUNTER_TYPES } from './types';
export const counterActions = {
increment: () => ({ type: COUNTER_TYPES.INCREMENT }),
decrement: () => ({ type: COUNTER_TYPES.DECREMENT }),
incrementByAmount: (amount) => ({
type: COUNTER_TYPES.INCREMENT_BY_AMOUNT,
payload: amount,
}),
};
5.3 TypeScript 支持
// types/store.ts
interface CounterState {
value: number;
status: 'idle' | 'loading' | 'succeeded' | 'failed';
error: string | null;
}
interface RootState {
counter: CounterState;
user: UserState;
}
// store/counterSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0,
status: 'idle',
error: null,
} as CounterState,
reducers: {
increment: (state) => {
state.value += 1;
},
incrementByAmount: (state, action: PayloadAction<number>) => {
state.value += action.payload;
},
},
});
6. 性能优化
6.1 避免不必要的渲染
// 使用 shallowEqual 进行浅比较
import { useSelector, shallowEqual } from 'react-redux';
function OptimizedComponent() {
const { value1, value2 } = useSelector(
state => ({
value1: state.counter.value1,
value2: state.counter.value2,
}),
shallowEqual
);
}
6.2 记忆化选择器
import { createSelector } from '@reduxjs/toolkit';
const selectItems = state => state.items;
const selectFilter = state => state.filter;
const selectFilteredItems = createSelector(
[selectItems, selectFilter],
(items, filter) => items.filter(item => item.type === filter)
);
7. 调试工具
7.1 Redux DevTools
// store/index.js
import { configureStore } from '@reduxjs/toolkit';
export const store = configureStore({
reducer: rootReducer,
devTools: process.env.NODE_ENV !== 'production',
});
8. 总结
8.1 核心要点
- 状态集中管理
- 单向数据流
- 纯函数更新
- 中间件扩展
8.2 使用建议
- 合理划分 state 结构
- 避免冗余的状态
- 使用 TypeScript 增加类型安全
- 注意性能优化
- 保持 action 和 reducer 的简单性