TypeScript Redux 在刷新页面时丢失状态

问题描述 投票:0回答:1

redux/reducer/cartReducer.ts

import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { CartReducerInitialState } from "../../types/reducer-types";
import { CartItem, ShippingInfo } from "../../types/types";

const initialState: CartReducerInitialState = {
    loading: false,
    cartItems: [],
    subtotal: 0,
    tax: 0,
    shippingCharges: 0,
    discount: 0,
    total: 0,
    shippingInfo: {
        address: "",
        city: "",
        state: "",
        country: "",
        pinCode: "",
    },
};

export const cartReducer = createSlice({
  name: "cartReducer",
  initialState,
  reducers: {
    addToCart: (state, action: PayloadAction<CartItem>) => {
      state.loading = true;

      const index = state.cartItems.findIndex(
        (i) => i.productId === action.payload.productId
      );

      if (index !== -1) state.cartItems[index] = action.payload;
      else state.cartItems.push(action.payload);
      state.loading = false;
    },

    removeCartItem: (state, action: PayloadAction<string>) => {
      state.loading = true;
      state.cartItems = state.cartItems.filter(
        (i) => i.productId !== action.payload
      );
      state.loading = false;
    }
  },
});

export const {
  addToCart,
  removeCartItem
} = cartReducer.actions;

redux/store.ts

import { configureStore } from "@reduxjs/toolkit";
import { userAPI } from "./api/userAPI";
import { userReducer } from "./reducer/userReducer";
import { productAPI } from "./api/productAPI";
import { cartReducer } from "./reducer/cartReducer";
import { persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import {combineReducers} from "@reduxjs/toolkit"; 

export const server = import.meta.env.VITE_SERVER;

const reducers = combineReducers({
    [userAPI.reducerPath]: userAPI.reducer,
    [productAPI.reducerPath]: productAPI.reducer,
    [userReducer.name]: userReducer.reducer,
    [cartReducer.name]: cartReducer.reducer           
});

const persistConfig = {
    key: 'root',
    storage,
    whitelist: ["cartReducer"]
};

const persistedReducer = persistReducer(persistConfig, reducers)

export const store = configureStore({
    reducer: persistedReducer,
    middleware: (getDefaultMiddleware) => 
        getDefaultMiddleware().concat([
            userAPI.middleware,
            productAPI.middleware
        ]),
});

export type RootState = ReturnType<typeof store.getState>

页面/Home.tsx

 const { cartItems, subtotal, tax, total, shippingCharges, discount } = useSelector((state: { cartReducer: CartReducerInitialState }) => state.cartReducer)
    
    const { data, isError, isLoading } = useLatestProductsQuery("")
    // console.log(data)
    console.log(cartItems)

    const dispatch = useDispatch()

    const addToCartHandler = (cartItem: CartItem) => {
        if(cartItem.stock < 1) return toast.error("Out of Stock")
        dispatch(addToCart(cartItem))
        toast.success("Item added to cart")
    }
     {
                            data?.products.map((i) => (
                                <ProductCard key={i._id} productId={i._id} name={i.name} price={i.price}
                                category={i.category} stock={i.stock} handler={addToCartHandler} photo={i.photo} />
                            ))
                        }

组件/ProductCard.tsx

type ProductProps = {
    productId: string
    photo: string
    name: string
    category: string 
    price: number
    stock: number
    handler: (cartItem: CartItem) => string | undefined
}

const ProductCard = ({
    productId,
    photo,
    name,
    category,
    price,
    stock,
    handler
}: ProductProps) => {
    return (
        <div className="product-card">
            <h3 className="category">{category.toUpperCase()}</h3>
            <img src={`${server}/${photo}`} alt={name} />
            <p>{name}</p>
            <span>HK$ {price}</span>
            <div>
                <button onClick={() => handler({
                    productId,
                    price,
                    name,
                    category,
                    photo,
                    stock,
                    quantity: 1
                })}>
                    <FaPlus />
                </button>

            </div>
        </div>
    )
}

类型/types.ts

export type CartItem = {
    productId: string
    photo: string
    name: string
    category: string
    price: number
    quantity: number
    stock: number
}

在这个项目中,我想维护当用户单击添加按钮时已添加的购物车的状态。即使我使用减速器正确注册了商店,

cartReducer
也无法维护单击按钮后添加的项目。到目前为止,我尝试添加
redux-persist
,但是当我点击添加按钮并刷新时,状态仍然无法保持。我按照 redux 中的文档进行了多次尝试,但仍然卡在这里,所以任何人都可以提供帮助来解决问题吗?

reactjs typescript redux redux-toolkit redux-persist
1个回答
0
投票

您似乎已经实现了大约一半的持久性设置。缺少的是创建一个

persistor
对象以及可能的
PersistGate

import { configureStore, combineReducers } from "@reduxjs/toolkit";
import {
  persistStore, // <-- add import
  persistReducer
} from 'redux-persist'
import storage from 'redux-persist/lib/storage';

import { userAPI } from "./api/userAPI";
import { userReducer } from "./reducer/userReducer";
import { productAPI } from "./api/productAPI";
import { cartReducer } from "./reducer/cartReducer";

export const server = import.meta.env.VITE_SERVER;

const reducers = combineReducers({
  [userAPI.reducerPath]: userAPI.reducer,
  [productAPI.reducerPath]: productAPI.reducer,
  [userReducer.name]: userReducer.reducer,
  [cartReducer.name]: cartReducer.reducer           
});

const persistConfig = {
  key: 'root',
  storage,
  whitelist: [cartReducer.name]
};

const persistedReducer = persistReducer(persistConfig, reducers)

export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) => 
    getDefaultMiddleware().concat([
      userAPI.middleware,
      productAPI.middleware
    ]),
});

export const persistor = persistStore(store); // <-- export persistor

export type RootState = ReturnType<typeof store.getState>

然后在 UI 中确保您使用 Redux

PersistGate
组件下的
Provider
包装应用程序。

示例:

import { PersistGate } from 'redux-persist/integration/react';
import { store, persistor } from './path/to/redux/store';

const AppRoot = () => {
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <App />
      </PersistGate>
    </Provider>
  );
};
© www.soinside.com 2019 - 2024. All rights reserved.