React Redux 状态管理:从基础到实战(TodoList 案例)

一、Redux 核心概念
  1. Store
    全局状态容器,存储应用所有状态
    $$ \text{Store} = {\text{state}, \text{reducers}, \text{middleware}} $$

  2. Action
    描述状态变更的普通对象,必须包含 type 属性

    { type: 'ADD_TODO', payload: 'Learn Redux' }
    

  3. Reducer
    纯函数,接收当前状态和 action,返回新状态
    $$ \text{newState} = \text{reducer}(\text{currentState}, \text{action}) $$

  4. Dispatch
    触发状态更新的唯一方式:store.dispatch(action)


二、React-Redux 集成
  1. Provider 组件
    包裹根组件,传递 store 到所有子组件

    import { Provider } from 'react-redux';
    import store from './store';
    
    ReactDOM.render(
      <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById('root')
    );
    

  2. connect 高阶组件
    连接 React 组件与 Redux store

    import { connect } from 'react-redux';
    
    const TodoList = ({ todos }) => ( /* JSX */ );
    
    const mapStateToProps = state => ({ todos: state.todos });
    export default connect(mapStateToProps)(TodoList);
    


三、TodoList 实战实现

1. 状态结构设计

{
  todos: [
    { id: 1, text: "Buy milk", completed: false },
    { id: 2, text: "Learn Redux", completed: true }
  ],
  filter: "SHOW_ALL" // SHOW_COMPLETED/SHOW_ACTIVE
}

2. Action 创建函数

// actions.js
let nextId = 0;

export const addTodo = text => ({
  type: 'ADD_TODO',
  payload: { id: nextId++, text, completed: false }
});

export const toggleTodo = id => ({
  type: 'TOGGLE_TODO',
  payload: id
});

3. Reducer 实现

// reducer.js
const initialState = { todos: [], filter: 'SHOW_ALL' };

export default (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 
            ? { ...todo, completed: !todo.completed } 
            : todo
        )
      };
    default:
      return state;
  }
};

4. 容器组件

// TodoListContainer.js
import { connect } from 'react-redux';
import { addTodo, toggleTodo } from './actions';

const TodoList = ({ todos, dispatch }) => (
  <div>
    <input 
      type="text" 
      onKeyPress={e => e.key === 'Enter' && dispatch(addTodo(e.target.value))}
    />
    <ul>
      {todos.map(todo => (
        <li 
          key={todo.id} 
          onClick={() => dispatch(toggleTodo(todo.id))}
          style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
        >
          {todo.text}
        </li>
      ))}
    </ul>
  </div>
);

const mapStateToProps = state => ({ todos: state.todos });
export default connect(mapStateToProps)(TodoList);

5. 过滤功能扩展

// 添加过滤器action
export const setFilter = filter => ({ type: 'SET_FILTER', payload: filter });

// 更新reducer
case 'SET_FILTER':
  return { ...state, filter: action.payload };

// 在组件中使用
const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_COMPLETED': return todos.filter(t => t.completed);
    case 'SHOW_ACTIVE': return todos.filter(t => !t.completed);
    default: return todos;
  }
};


四、最佳实践
  1. 使用 Redux Toolkit
    简化 action/reducer 创建:

    import { createSlice } from '@reduxjs/toolkit';
    
    const todoSlice = createSlice({
      name: 'todos',
      initialState: [],
      reducers: {
        addTodo: (state, action) => [...state, action.payload],
        toggleTodo: (state, action) => state.map(todo => 
          todo.id === action.payload ? {...todo, completed: !todo.completed} : todo
        )
      }
    });
    

  2. 异步处理
    使用 Redux Thunk 处理 API 请求:

    export const fetchTodos = () => async dispatch => {
      const response = await axios.get('/api/todos');
      dispatch({ type: 'LOAD_TODOS', payload: response.data });
    };
    

  3. 性能优化
    使用 React.memo 避免不必要的重渲染:

    const TodoItem = React.memo(({ todo, onToggle }) => (
      <li onClick={() => onToggle(todo.id)}>{todo.text}</li>
    ));
    


五、完整项目结构
src/
├── store/
│   ├── index.js       # Store 初始化
│   ├── actions.js     # Action 创建器
│   ├── reducers.js    # Root reducer
│   └── slices/        # Redux Toolkit 切片
├── components/        # 展示组件
└── containers/        # 容器组件

通过 TodoList 案例,可深入理解 Redux 单向数据流: $$ \text{Action} \rightarrow \text{Reducer} \rightarrow \text{Store} \rightarrow \text{View} \xrightarrow{\text{User Input}} \text{Action} $$ 该模式确保状态变更可预测且易于调试,适用于中大型应用开发。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐