Redux基础 #
一、Redux概述 #
1.1 什么是Redux #
Redux 是一个可预测的状态容器,基于 Flux 架构思想,用于管理应用状态。
1.2 三大原则 #
| 原则 | 说明 |
|---|---|
| 单一数据源 | 整个应用的状态存储在一个store中 |
| State只读 | 只能通过dispatch action来修改状态 |
| 纯函数修改 | Reducer是纯函数,接收旧状态和action,返回新状态 |
1.3 数据流 #
text
Action → Reducer → Store → View
↑ │
└──────────────────────────────┘
二、核心概念 #
2.1 Action #
Action 是描述事件的普通对象:
javascript
// Action类型常量
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';
// Action创建函数
function addTodo(text) {
return {
type: ADD_TODO,
payload: {
id: Date.now(),
text,
completed: false
}
};
}
function toggleTodo(id) {
return {
type: TOGGLE_TODO,
payload: { id }
};
}
2.2 Reducer #
Reducer 是纯函数,处理状态变化:
javascript
const initialState = {
todos: [],
filter: 'all'
};
function todoReducer(state = initialState, action) {
switch (action.type) {
case 'ADD_TODO':
return {
...state,
todos: [...state.todos, action.payload]
};
case 'TOGGLE_TODO':
return {
...state,
todos: state.todos.map(todo =>
todo.id === action.payload.id
? { ...todo, completed: !todo.completed }
: todo
)
};
case 'REMOVE_TODO':
return {
...state,
todos: state.todos.filter(todo => todo.id !== action.payload.id)
};
case 'SET_FILTER':
return {
...state,
filter: action.payload
};
default:
return state;
}
}
2.3 Store #
Store 是保存状态的地方:
javascript
import { createStore, combineReducers } from 'redux';
// 合并多个reducer
const rootReducer = combineReducers({
todos: todoReducer,
user: userReducer
});
// 创建store
const store = createStore(rootReducer);
// 获取状态
console.log(store.getState());
// 订阅变化
const unsubscribe = store.subscribe(() => {
console.log('State changed:', store.getState());
});
// 派发action
store.dispatch(addTodo('Learn Redux'));
// 取消订阅
unsubscribe();
三、在React中使用Redux #
3.1 安装 #
bash
npm install redux react-redux
3.2 Provider组件 #
javascript
import { Provider } from 'react-redux';
import { createStore } from 'redux';
const store = createStore(rootReducer);
function App() {
return (
<Provider store={store}>
<TodoApp />
</Provider>
);
}
3.3 useSelector获取状态 #
javascript
import { useSelector } from 'react-redux';
function TodoList() {
// 获取整个状态
const state = useSelector(state => state);
// 获取特定状态
const todos = useSelector(state => state.todos);
const filter = useSelector(state => state.filter);
// 计算派生状态
const filteredTodos = useSelector(state => {
switch (state.filter) {
case 'active':
return state.todos.filter(t => !t.completed);
case 'completed':
return state.todos.filter(t => t.completed);
default:
return state.todos;
}
});
return (
<ul>
{filteredTodos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
}
3.4 useDispatch派发Action #
javascript
import { useDispatch, useSelector } from 'react-redux';
import { addTodo, toggleTodo, removeTodo } from './actions';
function TodoApp() {
const dispatch = useDispatch();
const todos = useSelector(state => state.todos);
const [input, setInput] = useState('');
const handleAdd = () => {
if (input.trim()) {
dispatch(addTodo(input));
setInput('');
}
};
const handleToggle = (id) => {
dispatch(toggleTodo(id));
};
const handleRemove = (id) => {
dispatch(removeTodo(id));
};
return (
<div>
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleAdd()}
/>
<button onClick={handleAdd}>添加</button>
<ul>
{todos.map(todo => (
<li key={todo.id}>
<span
onClick={() => handleToggle(todo.id)}
style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
>
{todo.text}
</span>
<button onClick={() => handleRemove(todo.id)}>删除</button>
</li>
))}
</ul>
</div>
);
}
四、异步Action #
4.1 安装redux-thunk #
bash
npm install redux-thunk
4.2 配置中间件 #
javascript
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
const store = createStore(rootReducer, applyMiddleware(thunk));
4.3 创建异步Action #
javascript
// 同步Action
const fetchUsersRequest = () => ({ type: 'FETCH_USERS_REQUEST' });
const fetchUsersSuccess = (users) => ({
type: 'FETCH_USERS_SUCCESS',
payload: users
});
const fetchUsersFailure = (error) => ({
type: 'FETCH_USERS_FAILURE',
payload: error
});
// 异步Action (Thunk)
export const fetchUsers = () => {
return async (dispatch) => {
dispatch(fetchUsersRequest());
try {
const response = await fetch('/api/users');
const users = await response.json();
dispatch(fetchUsersSuccess(users));
} catch (error) {
dispatch(fetchUsersFailure(error.message));
}
};
};
4.4 在组件中使用 #
javascript
function UserList() {
const dispatch = useDispatch();
const { users, loading, error } = useSelector(state => state.users);
useEffect(() => {
dispatch(fetchUsers());
}, [dispatch]);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
五、项目结构 #
5.1 按功能组织 #
text
src/
├── actions/
│ ├── todoActions.js
│ └── userActions.js
├── reducers/
│ ├── todoReducer.js
│ ├── userReducer.js
│ └── index.js
├── store/
│ └── index.js
└── components/
├── TodoList.jsx
└── UserList.jsx
5.2 Ducks模式 #
javascript
// features/todos.js
// Actions
const ADD_TODO = 'todos/ADD_TODO';
const TOGGLE_TODO = 'todos/TOGGLE_TODO';
// Action Creators
export const addTodo = (text) => ({
type: ADD_TODO,
payload: { id: Date.now(), text, completed: false }
});
export const toggleTodo = (id) => ({
type: TOGGLE_TODO,
payload: { id }
});
// Reducer
const initialState = [];
export default function todosReducer(state = initialState, action) {
switch (action.type) {
case ADD_TODO:
return [...state, action.payload];
case TOGGLE_TODO:
return state.map(todo =>
todo.id === action.payload.id
? { ...todo, completed: !todo.completed }
: todo
);
default:
return state;
}
}
// Selectors
export const selectAllTodos = (state) => state.todos;
export const selectActiveTodos = (state) =>
state.todos.filter(t => !t.completed);
六、最佳实践 #
6.1 使用常量定义Action类型 #
javascript
// actionTypes.js
export const ADD_TODO = 'todos/ADD_TODO';
export const TOGGLE_TODO = 'todos/TOGGLE_TODO';
export const REMOVE_TODO = 'todos/REMOVE_TODO';
6.2 使用选择器 #
javascript
// selectors.js
export const selectTodos = (state) => state.todos;
export const selectFilter = (state) => state.filter;
export const selectFilteredTodos = createSelector(
[selectTodos, selectFilter],
(todos, filter) => {
switch (filter) {
case 'active':
return todos.filter(t => !t.completed);
case 'completed':
return todos.filter(t => t.completed);
default:
return todos;
}
}
);
// 使用
function TodoList() {
const filteredTodos = useSelector(selectFilteredTodos);
// ...
}
6.3 使用Redux DevTools #
javascript
import { createStore, applyMiddleware, compose } from 'redux';
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
composeEnhancers(applyMiddleware(thunk))
);
七、总结 #
| 概念 | 说明 |
|---|---|
| Store | 状态容器 |
| Action | 描述事件的对象 |
| Reducer | 纯函数处理状态变化 |
| Dispatch | 派发Action |
| Selector | 获取状态的函数 |
核心原则:
- 单一数据源
- State只读
- 纯函数修改状态
最后更新:2026-03-26