0

我在使用 createSlice 进行重构时遇到了麻烦,我是 redux-toolkit 的初学者,并且已经查看了文档但仍然遇到问题。如果有人能指出我正确的方向,那就太好了。这是工作代码


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;
  }
}
4

1 回答 1

0

您当前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);
  };

代码沙盒


创建AsyncThunk

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

createAsyncThunk如果我们考虑将警报打开为“待处理”操作并将警报视为“已完成”操作,我们可以利用这一点。它只获取一个参数,因此您需要将msgalertTypetimeout作为对象的属性传递。您可以使用 thunk 的唯一 ID,action.meta.requestId而不是创建自己的 ID。您还可以通过 访问操作的参数action.meta.arg

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

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;

代码沙盒

于 2021-08-14T04:51:19.670 回答