FumadocsZDecode
React

Redux 多组件状态管理

Redux 是一个 JavaScript 状态容器,通过集中式存储和单向数据流实现多个组件间的状态共享与通信。它是处理跨组件复杂状态的行业标准方案。


一、核心概念

Redux 的状态管理围绕三个核心概念展开:

Store:唯一的、全局的状态树。所有共享状态都存储在一个 store 对象中。

Action:描述发生了什么的普通对象,包含 type 字段表示操作类型,可选的 payload 携带数据。

Reducer:纯函数,接收当前状态和 action,返回新的状态。它决定了状态如何响应各种操作。

数据流是单向的:组件 dispatch 一个 action → reducer 处理 → store 更新 → 所有订阅的组件收到通知。


二、基本实现

创建 store

import { createStore } from 'redux'

const initialState = {
  count: 0,
  todos: [],
}

function reducer(state = initialState, action: any) {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 }
    case 'ADD_TODO':
      return { ...state, todos: [...state.todos, action.payload] }
    default:
      return state
  }
}

export const store = createStore(reducer)

在函数组件中使用(推荐方式)

使用 useSelector 获取状态,使用 useDispatch 发送 action:

import { useSelector, useDispatch } from 'react-redux'

function Counter() {
  const count = useSelector((state: any) => state.count)
  const dispatch = useDispatch()

  return (
    <div>
      <p>计数:{count}</p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>增加</button>
    </div>
  )
}

function TodoList() {
  const todos = useSelector((state: any) => state.todos)
  const dispatch = useDispatch()

  const handleAddTodo = (text: string) => {
    dispatch({ type: 'ADD_TODO', payload: text })
  }

  return (
    <div>
      {todos.map((todo, i) => (
        <li key={i}>{todo}</li>
      ))}
    </div>
  )
}

在类组件中使用(旧方式)

使用 connect 高阶组件将状态和 dispatch 方法映射到 props:

import { connect } from 'react-redux'

class Counter extends React.Component<any> {
  render() {
    const { count, increment } = this.props
    return (
      <div>
        <p>计数:{count}</p>
        <button onClick={increment}>增加</button>
      </div>
    )
  }
}

const mapStateToProps = (state: any) => ({
  count: state.count,
})

const mapDispatchToProps = (dispatch: any) => ({
  increment: () => dispatch({ type: 'INCREMENT' }),
})

export default connect(mapStateToProps, mapDispatchToProps)(Counter)

三、最佳实践

状态划分:只把跨组件共享的全局状态放在 Redux 中。组件的局部状态(如表单输入框的值)继续用 useState 管理。

状态扁平化:避免深层嵌套的状态结构。扁平的状态更易于更新和维护。

// ✗ 避免深层嵌套
const state = {
  user: {
    profile: {
      personal: {
        name: 'John',
      },
    },
  },
}

// ✓ 优先扁平结构
const state = {
  userName: 'John',
  userEmail: 'john@example.com',
}

Action 常量化:定义常量避免 action type 的拼写错误。

const INCREMENT = 'INCREMENT'
const ADD_TODO = 'ADD_TODO'

dispatch({ type: INCREMENT })

精确订阅:只订阅组件真正需要的状态片段,避免不必要的重新渲染。

// ✗ 订阅整个状态
const state = useSelector((s) => s)

// ✓ 只订阅需要的部分
const count = useSelector((s) => s.count)
const todos = useSelector((s) => s.todos)

Reducer 职责单一:为不同的状态片段创建不同的 reducer,然后用 combineReducers 组合。

import { createStore, combineReducers } from 'redux'

const countReducer = (state = 0, action: any) => {
  return action.type === 'INCREMENT' ? state + 1 : state
}

const todoReducer = (state: any[] = [], action: any) => {
  return action.type === 'ADD_TODO' ? [...state, action.payload] : state
}

const rootReducer = combineReducers({
  count: countReducer,
  todos: todoReducer,
})

const store = createStore(rootReducer)

四、性能优化

使用 React.memo 避免不必要的渲染

const TodoItem = React.memo(({ todo, onDelete }: any) => {
  return (
    <div>
      <span>{todo}</span>
      <button onClick={onDelete}>删除</button>
    </div>
  )
})

批量更新:避免在短时间内多次 dispatch,可以合并成一个 action。

// ✗ 多次 dispatch,触发多次重新渲染
dispatch({ type: 'SET_NAME', payload: 'John' })
dispatch({ type: 'SET_EMAIL', payload: 'john@example.com' })

// ✓ 一次 dispatch,一次重新渲染
dispatch({
  type: 'UPDATE_USER',
  payload: { name: 'John', email: 'john@example.com' },
})

一句话记住:Redux 通过一个全局 store 存储所有共享状态,组件通过 dispatch action 触发状态更新,reducer 定义状态如何变化,store 的订阅机制自动通知相关组件。合理划分状态、精确订阅、扁平化结构是维持性能的关键。

On this page