首页 > 解决方案 > 从另一个切片响应已完成的 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 将很容易。

标签: reduxredux-toolkit

解决方案


回答 上述策略的问题是我在 cartslice reducer clearCart 函数中使用了 return。删除退货解决了这个问题。我可以从 signOut thunk 成功调度 clearCart 并更新 currentUser 状态和 cartItems 状态。


推荐阅读