您当前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
如果我们考虑将警报打开为“待处理”操作并将警报视为“已完成”操作,我们可以利用这一点。它只获取一个参数,因此您需要将msg
、alertType
和timeout
作为对象的属性传递。您可以使用 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;
代码沙盒