电子商务应用程序中购物车的redux本地存储工具

w8ntj3qf  于 2023-02-23  发布在  其他
关注(0)|答案(2)|浏览(130)

我已经建立了一个电子商务应用程序,并需要购物车项目保持不变,如果用户刷新页面。我已经创建了一个切片在这个文件中的所有行动。我做了一些阅读redux-tooklit-persist,它听起来像是我的解决方案。我已经包括了reducer文件以及文件,其中包含“AddToCart”功能。

import { createSlice } from "@reduxjs/toolkit"

const initialState = {
  isCartOpen: false,
  cart: [],
  items: []
}

export const cartSlice = createSlice({
  name: "cart",
  initialState,
  reducers: {
    setItems: (state, action) => {
      state.items = action.payload
    },
    // Add item to cart
    addToCart: (state, action) => {
      state.cart = [...state.cart, action.payload.item]
    },
    // Remove item from cart
    removeFromCart: (state, action) => {
      state.cart = state.cart.filter((item) => item.id !== action.payload.id)
    },
    // Increase count in cart
    increaseCount: (state, action) => {
      state.cart = state.cart.map((item) => {
        if (item.id === action.payload.id) {
          item.count++
        }
        return item
      })
    },
    // Decrease count in cart
    decreaseCount: (state, action) => {
      state.cart = state.cart.map((item) => {
        if (item.id === action.payload.id && item.count > 1) {
          item.count--
        }
        return item
      })
    },
    setIsCartOpen: (state) => {
      state.isCartOpen = !state.isCartOpen
    }
  }
})

//Export
export const {
  setItems,
  addToCart,
  removeFromCart,
  increaseCount,
  decreaseCount,
  setIsCartOpen
} = cartSlice.actions

export default cartSlice.reducer

这是我的项目.jsx

import { useState } from "react"
import { useDispatch } from "react-redux"
import { IconButton, Box, Typography, useTheme, Button } from "@mui/material"
import AddIcon from "@mui/icons-material/Add"
import RemoveIcon from "@mui/icons-material/Remove"
import { shades } from "../theme"
import { addToCart } from "../state"
import { useNavigate } from "react-router-dom"
    
const Item = ({ item, width }) => {
  const navigate = useNavigate()
  const dispatch = useDispatch()
  const [count, setCount] = useState(1)
  const [isHovered, setIsHovered] = useState(false)
  const {
    palette: { neutral }
  } = useTheme()
    
  // Destructure from attributes
  const { category, price, name, image } = item.attributes
  const {
    data: {
      attributes: {
        formats: {
          medium: { url }
        }
      }
    }
  } = image
    
  return (
    <Box width={width}>
      <Box
        position="relative"
        onMouseOver={() => setIsHovered(true)}
        onMouseOut={() => setIsHovered(false)}
      >
        <img
          alt={item.name}
          width="300px"
          height="400px"
          src={`http://localhost:1337${url}`}
          onClick={() => navigate(`/item/${item.id}`)}
          style={{ cursor: "pointer" }}
        />
        <Box
          display={isHovered ? "block" : "none"}
          position="absolute"
          bottom="10%"
          left="0"
          width="100%"
          padding="0 5%"
        >
          <Box display="flex" justifyContent="space-between">
            <Box
              display="flex"
              alignItems="center"
              backgroundColor={shades.neutral[100]}
              borderRadius="3px"
            >
              <IconButton onClick={() => setCount(Math.max(count - 1, 1))}>
                <RemoveIcon />
              </IconButton>
              <Typography color={shades.primary[300]}>
                {count}
              </Typography>
              <IconButton onClick={() => setCount(count + 1)}>
                <AddIcon />
              </IconButton>
            </Box>
            <Button
              onClick={() => {
                dispatch(addToCart({ item: { ...item, count } }))
              }}
              sx={{
                backgroundColor: shades.primary[300],
                color: "white"
              }}
            >
              Add to Cart
            </Button>
          </Box>
        </Box>
      </Box>
    
      <Box mt="3px">
        <Typography variant="subtitle2" color={neutral.dark}>
          {category
            .replace(/([A-Z])/g, " $1")
            .replace(/^./, (str) => str.toUpperCase())
          }
        </Typography>
        <Typography>{name}</Typography>
        <Typography fontWeight="bold">${price}</Typography>
      </Box>
    </Box>
  )
}
    
export default Item
vbkedwbf

vbkedwbf1#

redux-persistreact Redux状态持久性的标准。
虽然您可以像Mohammad的答案那样单独初始化和持久化从&到localStorage的状态切片,但这是不明智的,因为持久化到localStorage的行为是被认为是*纯函数的副作用。
最好将其抽象为一个定制的中间件。RTK维护人员已经使使用createListenerMiddleware创建中间件侦听器变得相当容易。您可以创建一个中间件侦听器,它对特定的操作或条件做出React,以将存储持久化到localStorage。
我建议使用redux-persist,如果你已经熟悉了reactredux-toolkit,这是一个相当快的设置/集成。
示例:

import { configureStore, combineReducers } from "@reduxjs/toolkit";
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import { Provider } from "react-redux";
import { PersistGate } from 'redux-persist/integration/react';
import cartReducer from '../path/to/cartSlice';

const persistConfig = {
  key: 'root',
  storage,
};

const rootReducer = combineReducers({
  ...other reducers...
  cart: cartReducer,
});
 
const persistedReducer = persistReducer(persistConfig, rootReducer);

export const store = configureStore({
  reducer: persistedReducer,
  ...any middlewares and other configuration properties...
});
const persistor = persistStore(store);

此时,我还将导出一个 Package 器组件,用于呈现react-reduxProvider组件和redux-persistPersistGate组件。

export const PersistedProvider = ({ children }) => (
  <Provider store={store}>
    <PersistGate loading={null} persistor={persistor}>
      {children}
    </PersistGate>
  </Provider>
);

现在,您可以使用PersistedProvider组件进行 Package ,而不是使用Provider组件 Package App组件,并将Redux存储提供给应用***,***持久化redux状态。

import { PersistedProvider } from '../path/to/store';

...

<PersistedProvider>
  <App />
</PersistedProvider>
58wvjzkj

58wvjzkj2#

我的朋友,你必须使用localStorage来存储浏览器中的数据:

const initialState = {
isCartOpen: false,
cart: localStorage.get("cart") ? JSON.parse(localStorage.get("cart")) : [],
items: []
}

export const cartSlice = createSlice({
  name: "cart",
  initialState,
  reducers: {
    addToCart: (state, action) => {
        state.cart = [...state.cart, action.payload.item];
        localStorage.set("cart", JSON.stringify(state.cart))
    },
  }
})

在这里,每次您调度addToCart时,您的数据将保存在redux和localStorage中,当您刷新页面时,您的redux将填充localStorage。我只更改了其中一个Reducer,您必须根据localStorage和您的redux更改所有Redux。如果您遇到问题,请告诉我,我会向您解释。

相关问题