Skip to content

Redux 状态管理器

Redux 核心主要有 Store、Action、Reducer。

数据流向:在 Redux 中,数据是单向流动的。简单来说就是:

  • 用户在界面上进行操作(如点击按钮)。
  • 触发一个 Action 的派发(dispatch)。
  • Store 调用对应的 Reducer,传入旧的 state 和这个 Action。
  • Reducer 根据 Action 的类型返回一个新的 state。
  • Store 的 state 更新,React 组件监听到变化并重新渲染。

首先需要安装 react-redux 和 @reduxjs/toolkit 这两个包

bash
npm install react-redux @reduxjs/toolkit
npm install react-redux @reduxjs/toolkit

创建 Redux Store

创建一个 src/store/store.js 文件

js
import { configureStore } from "@reduxjs/toolkit";

export const store = configureStore({
  reducer: {
    // 这里将是我们之后创建的各个模块的 reducer
  },
});
import { configureStore } from "@reduxjs/toolkit";

export const store = configureStore({
  reducer: {
    // 这里将是我们之后创建的各个模块的 reducer
  },
});

将 Store 提供给 React 应用

整个 React 应用都可以访问到 Redux Store 了。

js
// src/index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { store } from "./store/store";
import { Provider } from "react-redux";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);
// src/index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { store } from "./store/store";
import { Provider } from "react-redux";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

创建 Slice(状态切片)

在 Vuex 中,有 state, mutations, actions, getters 这些概念。在 Redux Toolkit 中,一个类似的概念叫做 Slice。Slice 将与某个功能相关的 state、reducers(类似 mutations)和 actions 集中在一个文件里进行管理。

js
// src/features/counter/counterSlice.js
import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  value: 0,
};

export const counterSlice = createSlice({
  name: "counter", // slice 的名称
  initialState, // 初始状态
  // 定义 reducers,这里的函数会自动生成对应的 actions
  reducers: {
    increment: (state) => {
      // Redux Toolkit 内部使用了 Immer,所以可以直接“修改” state
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    // 接收 payload 的 action
    incrementByAmount: (state, action) => {
      state.value += action.payload;
    },
  },
});

// 导出 reducers 中定义的 action creator 函数
export const { increment, decrement, incrementByAmount } = counterSlice.actions;

// 默认导出 reducer
export default counterSlice.reducer;
// src/features/counter/counterSlice.js
import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  value: 0,
};

export const counterSlice = createSlice({
  name: "counter", // slice 的名称
  initialState, // 初始状态
  // 定义 reducers,这里的函数会自动生成对应的 actions
  reducers: {
    increment: (state) => {
      // Redux Toolkit 内部使用了 Immer,所以可以直接“修改” state
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
    // 接收 payload 的 action
    incrementByAmount: (state, action) => {
      state.value += action.payload;
    },
  },
});

// 导出 reducers 中定义的 action creator 函数
export const { increment, decrement, incrementByAmount } = counterSlice.actions;

// 默认导出 reducer
export default counterSlice.reducer;

将 Slice 的 Reducer 添加到 Store 中

js
// src/app/store.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice"; // 导入 counter 的 reducer

export const store = configureStore({
  reducer: {
    counter: counterReducer, // 将 counter reducer 添加到 store 中
  },
});
// src/app/store.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice"; // 导入 counter 的 reducer

export const store = configureStore({
  reducer: {
    counter: counterReducer, // 将 counter reducer 添加到 store 中
  },
});

在 React 组件中使用 Redux State 和 Actions

react-redux 提供了两个关键的 Hooks 来实现这一点:useSelector 和 useDispatch。

js
// src/features/counter/Counter.js
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { decrement, increment, incrementByAmount } from "./counterSlice";

export function Counter() {
  // useSelector 用于从 store 中读取 state
  const count = useSelector((state) => state.counter.value);
  // useDispatch 用于获取 dispatch 函数,派发 action
  const dispatch = useDispatch();

  return (
    <div>
      <div>
        <button
          aria-label="Increment value"
          onClick={() => dispatch(increment())}
        >
          增加
        </button>
        <span>{count}</span>
        <button
          aria-label="Decrement value"
          onClick={() => dispatch(decrement())}
        >
          减少
        </button>
        <button onClick={() => dispatch(incrementByAmount(5))}>增加 5</button>
      </div>
    </div>
  );
}
// src/features/counter/Counter.js
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { decrement, increment, incrementByAmount } from "./counterSlice";

export function Counter() {
  // useSelector 用于从 store 中读取 state
  const count = useSelector((state) => state.counter.value);
  // useDispatch 用于获取 dispatch 函数,派发 action
  const dispatch = useDispatch();

  return (
    <div>
      <div>
        <button
          aria-label="Increment value"
          onClick={() => dispatch(increment())}
        >
          增加
        </button>
        <span>{count}</span>
        <button
          aria-label="Decrement value"
          onClick={() => dispatch(decrement())}
        >
          减少
        </button>
        <button onClick={() => dispatch(incrementByAmount(5))}>增加 5</button>
      </div>
    </div>
  );
}

程序员小洛文档