使用 createSlice reduxtoolkit 进行重构

Refactoring with createSlice reduxtoolkit

我在使用 createSlice 进行重构时遇到问题,我是 redux-toolkit 的初学者并且已经查看了文档,但仍然 problems.if 有人可以为我指出正确的方向,这太棒了。这是工作代码


const SET_ALERT = 'setAlert';
const REMOVE_ALERT = 'alertRemoved';

export const setAlert =
  (msg, alertType, timeout = 5000) =>
  (dispatch) => {
    const id = nanoid();
    dispatch({
      type: SET_ALERT,
      payload: { msg, alertType, id },
    });

    setTimeout(() => dispatch({ type: REMOVE_ALERT, payload: id }), timeout);
  };

const initialState = [];

export default function alertReducer(state = initialState, action) {
  const { type, payload } = action;

  switch (type) {
    case SET_ALERT:
      return [...state, payload];
    case REMOVE_ALERT:
      return state.filter((alert) => alert.id !== payload);
    default:
      return state;
  }
}

您当前的 setAlert 动作创建者创建了一个 thunk 动作(一个以 dispatch 作为参数的动作),因此它不能是由 createSlice 自动生成的动作创建者。


创建切片

您可以使设置与现在的设置非常相似。您将有两个单独的操作来设置和删除警报,以及一个用于调度两者的 thunk。底层基本操作 可以 使用 createSlice.

创建
import { createSlice, nanoid } from "@reduxjs/toolkit";

const slice = createSlice({
  name: "alerts",
  initialState: [],
  reducers: {
    addAlert: (state, action) => {
      // modify the draft state and return nothing
      state.push(action.payload);
    },
    removeAlert: (state, action) => {
      // replace the entire slice state
      return state.filter((alert) => alert.id !== action.payload);
    }
  }
});

const { addAlert, removeAlert } = slice.actions;

export default slice.reducer;

export const setAlert = (msg, alertType, timeout = 5000) =>
  (dispatch) => {
    const id = nanoid();
    dispatch(addAlert({ msg, alertType, id }));

    setTimeout(() => dispatch(removeAlert(id)), timeout);
  };

CodeSandbox


createAsyncThunk

下一节完全没有必要,而且过于“棘手”。

如果我们考虑将警报打开为 'pending' 操作并将警报关闭为 'fulfilled' 操作,我们可以使用 createAsyncThunk。它只有一个参数,因此您需要将 msgalertTypetimeout 作为对象的属性传递。您可以使用 thunk 的唯一 ID,即 action.meta.requestId 而不是创建您自己的 ID。您还可以通过 action.meta.arg.

访问操作的参数

如果需要,您仍然可以使用 createSlice,但除非您有其他操作,否则与 createReducer 相比没有任何优势。您将使用 extraReducers 属性 而不是 reducers.

来响应两个 thunk 操作
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";

export const handleAlert = createAsyncThunk( "alert/set", (arg) => {
  const { timeout = 5000 } = arg;
  return new Promise((resolve) => {
    setTimeout(() => resolve(), timeout);
  });
});

export default createReducer(initialState, (builder) =>
  builder
    .addCase(handleAlert.pending, (state, action) => {
      const { alertType, msg } = action.meta.arg;
      const id = action.meta.requestId;
      // modify the draft state and don't return anything
      state.push({ alertType, msg, id });
    })
    .addCase(handleAlert.fulfilled, (state, action) => {
      const id = action.meta.requestId;
      // we are replacing the entire state, so we return the new value
      return state.filter((alert) => alert.id !== id);
    })
);

示例组件

import { handleAlert } from "../store/slice";
import { useSelector, useDispatch } from "../store";

export const App = () => {
  const alerts = useSelector((state) => state.alerts);
  const dispatch = useDispatch();

  return (
    <div>
      {alerts.map((alert) => (
        <div key={alert.id}>
          <strong>{alert.alertType}</strong>
          <span>{alert.msg}</span>
        </div>
      ))}
      <div>
        <button
          onClick={() =>
            dispatch(
              handleAlert({
                alertType: "success",
                msg: "action was completed successfully",
                timeout: 2000
              })
            )
          }
        >
          Success
        </button>
        <button
          onClick={() =>
            dispatch(
              handleAlert({
                alertType: "warning",
                msg: "action not permitted"
              })
            )
          }
        >
          Warning
        </button>
      </div>
    </div>
  );
};

export default App;

CodeSandbox