redux - 从另一个切片响应已完成的 CreateAsyncThunk
问题描述
我有一个简单的电子商务应用程序,正在从 vanilla redux 迁移到 redux-toolkit。我有 2 个切片,一个 userSlice 和一个 cartSlice。我要做的是在我的 signOut createAsyncThunk 得到满足时从 cartSlice 触发 clearCart 操作。
我的用户切片:
import {
createSlice,
createSelector,
createAsyncThunk,
isAnyOf,
} from "@reduxjs/toolkit";
import {
auth,
googleProvider,
facebookProvider,
getSnapshotFromUserAuth,
getCurrentUser,
} from "../../firebase/firebase.utils";
//state
const initialState = {
currentUser: null,
error: null,
};
//signIn with google async thunk
export const signInWithGoogle = createAsyncThunk(
"user.signInWithGoogle",
async (_, { rejectWithValue }) => {
try {
const { user } = await auth.signInWithPopup(googleProvider);
return getSnapshotFromUserAuth(user);
} catch (error) {
return rejectWithValue({ error: error.message });
}
}
);
//sign in with email and password
export const signInWithEmailAndPassword = createAsyncThunk(
"user.emailSignIn",
async ({ email, password }, { rejectWithValue }) => {
try {
const { user } = await auth.signInWithEmailAndPassword(email, password);
return getSnapshotFromUserAuth(user);
} catch (error) {
return rejectWithValue(error.message);
}
}
);
//get current user
export const checkUserSession = createAsyncThunk(
"user.getCurrentUser",
async (_, { rejectWithValue }) => {
try {
const userAuth = await getCurrentUser();
if (!userAuth) {
return;
}
return getSnapshotFromUserAuth(userAuth);
} catch (error) {
return rejectWithValue(error.message);
}
}
);
//sign out user
export const signOut = createAsyncThunk(
"user.signOut",
async (_, { rejectWithValue }) => {
try {
await auth.signOut();
} catch (error) {
return rejectWithValue(error.message);
}
}
);
//user slice
export const userSlice = createSlice({
name: "user",
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(signOut.fulfilled, (state) => {
state.currentUser = null;
})
.addMatcher(
isAnyOf(
signInWithGoogle.fulfilled,
signInWithEmailAndPassword.fulfilled,
checkUserSession.fulfilled
),
(state, { payload }) => {
state.currentUser = payload;
}
)
.addMatcher(
isAnyOf(
signOut.rejected,
signInWithGoogle.rejected,
signInWithEmailAndPassword.rejected,
checkUserSession.rejected
),
(state, { payload }) => {
state.error = payload;
}
);
},
});
//reducer export
export default userSlice.reducer;
//selectors export
const selectUser = (state) => state.user;
export const selectCurrentUser = createSelector(
[selectUser],
(user) => user.currentUser
);
export const selectError = createSelector([selectUser], (user) => user.error);
和我的购物车切片
import { createSlice, createSelector } from "@reduxjs/toolkit";
import { addItemToCart, removeItemFromCart } from "../../redux/cart/cart.utils";
//sttate
const initialState = {
hidden: true,
cartItems: [],
};
//cart slice
export const cartSlice = createSlice({
name: "cart",
initialState,
reducers: {
toggleCartHidden: (state) => {
state.hidden = !state.hidden;
},
addItem: (state, { payload }) => {
state.cartItems = addItemToCart(state.cartItems, payload);
},
clearItemFromCart: (state, { payload }) => {
state.cartItems = state.cartItems.filter(
(cartItem) => cartItem.id !== payload.id
);
},
removeItem: (state, { payload }) => {
state.cartItems = removeItemFromCart(state.cartItems, payload);
},
clearCart: (state) => {
return (state.cartItems = []);
},
},
});
//export action creators
export const {
toggleCartHidden,
addItem,
clearItemFromCart,
removeItem,
clearCart,
} = cartSlice.actions;
//export reducer
export default cartSlice.reducer;
//export selectors
const selectCart = (state) => state.cart;
export const selectCartItems = createSelector(
[selectCart],
(cart) => cart.cartItems
);
export const selectCartHidden = createSelector(
[selectCart],
(cart) => cart.hidden
);
export const selectCartTotal = createSelector([selectCartItems], (cartItems) =>
cartItems.reduce(
(accumulatedQuantity, cartItem) =>
accumulatedQuantity + cartItem.quantity * cartItem.price,
0
)
);
export const selectCartItemsCount = createSelector(
[selectCartItems],
(cartItems) =>
cartItems.reduce(
(accumulatedQuantity, cartItem) =>
accumulatedQuantity + cartItem.quantity,
0
)
);
按照 redux 工具包提供的指导方针,我尝试从我的 cartSlice 导入我的 clearCart 操作,并在我的 SignOut thunk 中使用 thunkAPI 调度方法在等待 auth.signOut() 之后调度 clearCart 但后来我得到了一个拒绝状态,因为 Immer 抱怨我是既返回新值又修改草稿。
有人可以告诉我我在这里想念什么吗?使用 vanilla Redux,订阅我的 SIGNOUT_SUCCESS 操作并创建一个 saga 以产生 clearCart 将很容易。
解决方案
回答 上述策略的问题是我在 cartslice reducer clearCart 函数中使用了 return。删除退货解决了这个问题。我可以从 signOut thunk 成功调度 clearCart 并更新 currentUser 状态和 cartItems 状态。
推荐阅读
- python - 询问输入时代码中断的原因是什么?
- python - 在本地主机窗口中运行 django + apache
- python - setuptools如何在python setup.py test命令上安装测试依赖
- reactjs - 如何在 React 中将 Props 传递给组件
- buffer - OSMnx - Euclidean Buffers Around Point
- c - 需要知道如何在c中按空格解析单词。还需要知道我是否正确分配内存?
- scala - 这个scala语法是什么意思?
- shell - 在括号之间添加/修改文本
- java - jvm如何加载不同的jar但相同的包名和类名?
- python-2.7 - 如何将所有对象添加到 Python 中的空列表中?