Redux Store 简介

112 阅读5分钟

Redux 是 React 中用于全局状态管理的一个工具。它允许开发者在大型应用中集中管理应用的状态,使得状态的变化更加可预测和易于调试。Redux 的核心思想是将应用的所有状态存储在一个全局的 store 中,并通过严格定义的方式来修改这些状态。

Redux Store 的作用

  1. 集中管理状态:所有组件的状态都集中在一个 store 中,这样可以避免多个组件之间传递 props,简化组件间的通信。
  2. 可预测性:通过 reducer 函数来管理状态的变更,所有状态的变更都是通过 actions 明确的,保证了状态的变化是可预测和可追踪的。
  3. 调试友好:Redux 提供了强大的调试工具,比如 Redux DevTools,可以查看每一次状态的变化,回溯历史状态。
  4. 跨组件共享状态:即使两个没有直接关系的组件,也可以通过 store 来共享数据,而不必通过中间组件传递数据。

Redux 的核心概念

  • Store:应用的单一状态树,所有状态都存储在这里。
  • Action:描述状态变化的事件对象,通常包含一个 type 字段和其他数据。
  • Reducer:纯函数,根据当前的状态和 action 来生成新的状态。
  • Dispatch:用于触发 action 的方法。

Redux 的工作流程

  1. 组件通过 dispatch 方法发出一个 action。
  2. action 会被传递给 reducer 函数,reducer 根据当前的状态和传递进来的 action 来返回新的状态。
  3. store 根据 reducer 返回的状态更新,并通知所有订阅了 store 的组件。

代码示例

1. 创建 Redux Store

import { createStore } from 'redux';

// 定义初始状态
const initialState = {
  count: 0,
};

// 定义 reducer 函数
const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
};

// 创建 store
const store = createStore(counterReducer);

export default store;

或者直接派发


import { createStore } from 'redux';

// 定义初始状态
const initialState = {
  count: 0,
};

// 定义 reducer 函数
const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
};

// 创建 store
const store = createStore(counterReducer);

// 订阅 store 状态变化
store.subscribe(() => {
  console.log('Store changed:', store.getState());
});

// 派发 actions
store.dispatch({ type: 'INCREMENT' }); // 输出: Store changed: { count: 1 }
store.dispatch({ type: 'DECREMENT' }); // 输出: Store changed: { count: 0 }

2. 组件使用 Redux Store

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

const Counter = () => {
  // 读取 store 中的 count 状态
  const count = useSelector((state) => state.count);
  const dispatch = useDispatch();

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>增加</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>减少</button>
    </div>
  );
};

export default Counter;

3. Provider 将 Store 注入组件树

在根组件中,通过 Provider 组件将 Redux store 注入到整个应用中。

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import Counter from './Counter';

ReactDOM.render(
  <Provider store={store}>
    <Counter />
  </Provider>,
  document.getElementById('root')
);

在 Redux 中,如果有多个 reducer 函数,通常会将它们合并成一个主 reducer,这样 Redux 可以根据 action.type 来判断应该由哪个 reducer 处理相应的 action。Redux 提供了 combineReducers 函数来合并多个 reducer。

每个子 reducer 只处理其负责的状态片段,而不是整个应用的状态树。Redux 会根据你定义的 key,将不同的 reducer 对应的状态片段合并到整个应用的状态树中。

多个 reducer 的管理:combineReducers

下面是一个使用多个 reducer 的示例,通过 combineReducers 将它们合并起来。

代码示例

1. 定义多个 reducer

import { combineReducers, createStore } from 'redux';

// 定义初始状态
const initialCounterState = { count: 0 };
const initialTodoState = { todos: [] };

// 定义第一个 reducer:管理计数器状态
const counterReducer = (state = initialCounterState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
};

// 定义第二个 reducer:管理待办事项状态
const todoReducer = (state = initialTodoState, action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return { ...state, todos: [...state.todos, action.payload] };
    case 'REMOVE_TODO':
      return { ...state, todos: state.todos.filter((todo, index) => index !== action.index) };
    default:
      return state;
  }
};

// 使用 combineReducers 将多个 reducer 合并
const rootReducer = combineReducers({
  counter: counterReducer,
  todos: todoReducer,
});

// 创建 store
const store = createStore(rootReducer);

在这里,我们定义了两个 reducer:

  • counterReducer 处理计数器相关的状态。
  • todoReducer 处理待办事项列表。

然后通过 combineReducers 将它们合并到 rootReducer,并将 counterReducer 关联到 counter 状态,todoReducer 关联到 todos 状态。

2. 如何使用合并后的状态

当使用多个 reducer 后,状态树将会按照合并时定义的 key 来划分。例如,counter 对应 counterReducer 的状态片段,todos 对应 todoReducer 的状态片段。

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

const App = () => {
  const count = useSelector((state) => state.counter.count); // 获取 counterReducer 中的 count 状态
  const todos = useSelector((state) => state.todos.todos);   // 获取 todoReducer 中的 todos 状态
  const dispatch = useDispatch();

  const addTodo = () => {
    const newTodo = prompt("Enter a new todo:");
    dispatch({ type: 'ADD_TODO', payload: newTodo });
  };

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>增加</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>减少</button>

      <h2>Todos:</h2>
      <ul>
        {todos.map((todo, index) => (
          <li key={index}>{todo}</li>
        ))}
      </ul>
      <button onClick={addTodo}>添加待办事项</button>
    </div>
  );
};

export default App;

在这个组件中:

  • 即使是不同的Reducertpye 也不能重复。

  • 运行dispatch({ type: 'ADD_TODO', payload: newTodo } 或 dispatch({ type: 'DECREMENT' }) 时, Redux 会将这个 action 对象的 [type] 传递给所有的 reducer。这个 action 是一个包含 type 字段的 JavaScript 对象,type 字段告诉 reducer 需要进行什么样的状态变化。

  • useSelector((state) => state.counter.count) 获取了 counterReducer 中管理的 count 状态。

  • useSelector((state) => state.todos.todos) 获取了 todoReducer 中管理的 todos 列表。

combineReducers 的工作机制

combineReducers 的原理是将多个 reducer 合并为一个大的 reducer。当你 dispatch 一个 action 时,Redux 会将 action 传递给所有的子 reducer,并由每个子 reducer 决定是否对该 action 做出反应。最终的结果是各个子 reducer 返回的新状态片段被合并成整个状态树。

总结

  • 通过 combineReducers 可以将多个 reducer 合并,形成一个统一的 rootReducer
  • 每个 reducer 负责管理自己状态树中的一部分。
  • 通过 useSelector 来选择特定状态片段,并通过 dispatch 不同的 action 来触发状态更新。