I'm trying to make an ecommerce for my personal project and I'm trying to use everything I've learned to do so. I currently have this code that allows you to store cartItems
in a local Storage, but I believe it's incorrect what I did because in this scenario, for example, user 1
added his items to the cart or products to the cart, and then user 2
can access or have the same cart when I login with them. Which is the best practice or choice for the user to save cartItems
? Or, rather, what should I do?
Currently the technology I use the M(ongoDB)E(xpress)R(eact)N(odejs)G(raphql) and Apollo for my state management.
import { createContext, useState, useContext, useEffect } from "react";
import { AuthContext } from "../auth";
export const CartContext = createContext();
export const CartProvider = ({ children }) => {
const { user } = useContext(AuthContext);
const cartFromLocalStorage =
(typeof window !== "undefined" &&
JSON.parse(localStorage.getItem("cart"))) ||
[];
const [cartItems, setCartItem] = useState(cartFromLocalStorage);
useEffect(() => {
if (typeof window !== "undefined") {
if (user) { // This just shows if the user is loggedIn
localStorage.setItem("cart", JSON.stringify(cartItems));
}
}
}, [cartItems]);
return (
<CartContext.Provider value={[cartItems, setCartItem]}>
{children}
</CartContext.Provider>
);
};
This is my CartContext
, where I can see what the user has added to their cart and call it whenever I want because it's a context that doesn't require to pass props to a component.
import { useContext } from "react";
import { useQuery } from "@apollo/react-hooks";
import { FETCH_PRODUCTS_QUERY } from "../util/graphql/Queries";
import { Grid, Transition } from "semantic-ui-react";
import ProductCard from "../components/products/ProductCard";
import { CartContext } from "../context/cart/CartContext";
function Shop() {
const { loading, data: Products } = useQuery(FETCH_PRODUCTS_QUERY);
const { getProducts: products } = { ...Products };
const [cartItems, setCartItems] = useContext(CartContext);
const addToCart = (product) => {
const exist = cartItems.find((x) => x.id === product.id);
if (exist) {
setCartItems(
cartItems.map((x) =>
x.id == product.id ? { ...exist, quantity: exist.quantity + 1 } : x
)
);
} else {
setCartItems([...cartItems, { ...product, quantity: 1 }]);
}
};
const ProductList = products?.map((product) => (
<Grid.Column key={product.id} style={{ marginBottom: 20 }}>
<ProductCard
product={product}
addToCart={(product) => addToCart(product)}
/>
</Grid.Column>
));
return (
<>
<Grid columns={3}>
<Grid.Row className="page-title">
<h1>Recent Products</h1>
</Grid.Row>
<Grid.Row>
{loading ? (
<h1>Loading products..</h1>
) : (
<Transition.Group>{ProductList}</Transition.Group>
)}
</Grid.Row>
</Grid>
</>
);
}
export default Shop;
This is my Shop or where the Product is located as shown I passed the addToCart function
to the ProductCard
Component.
import { Image, Card } from "semantic-ui-react";
import Link from "next/link";
import Rating from "../reviews/Rating";
function ProductCard({ product, addToCart }) {
const {
id,
name,
featureImage,
productCurrentPrice,
productPreviousPrice,
rating,
numReviews,
} = product;
return (
<>
<Card>
<Image
src={featureImage}
width={200}
height={200}
alt="Product Image"
className="product-image"
/>
<Card.Content>
<Card.Header>
<Link href={`/products/${id}`}>{name}</Link>
</Card.Header>
<Card.Meta>
<span className="date">
₱{productCurrentPrice.toLocaleString()}
</span>
<span className="date">
<strike>₱{productPreviousPrice.toLocaleString()}</strike>
</span>
<span className="header">{percentOff} % OFF</span>
</Card.Meta>
</Card.Content>
<Card.Content extra>
<div className="ui two buttons">
<button
className="ui basic green button"
onClick={() => addToCart(product)}
>
Add To Cart
</button>
</div>
</Card.Content>
</Card>
</>
);
}
export default ProductCard;
This is my ProductCard Component which when addToCart it will go to the localStorage just like this:
As shown above, the image the cart key
is where all the products I added is inputted there. even when I logout the cartItem
is still shown there, which it should not.
If you need anymore clarification or explanation, I can provide it, if code I will also provide I will be transparent as I can.
Since each user has their own unique cart available, you can save the cart info the along with the userId/username of the current user as identifier. So when a user logs in you can just fetch the their cart using that identifier of the user
usually for storing such sensitive data it is better to save them directly in your DB rather than the local storage.
You can create an async Api call such that whenever you add items to cart, your corresponding data in table is also updated. Example a "Cart" table containing the current cart details of all users