Я строю веб-сайт электронной коммерции, используя Next.js, TypeScript, MongoDB и NextAuth.js. Я по-разному обращаюсь к корзине для покупок для гостевых пользователей и входа в систему: < /p>
Гостевые пользователи: CAR Пользовательский документ MongoDB. Этого не происходит для гостевых пользователей (Cart LocalStorage работает нормально). < /P>
Как это исправить? Похоже, что код в Cartcontext может быть причиной при попытке объединить корзину. < /P>
cartcontext: < /p>
"use client";
// Good way to manage global state(especially where you need access to multiple components)
import React, {
createContext,
useContext,
useState,
ReactNode,
useEffect,
} from "react";
import { useSession } from "next-auth/react";
export interface CartItem {
_id: string;
name: string;
image: string;
price: number;
size?: string;
quantity: number;
}
// functions go here
interface CartContextType {
cart: CartItem[];
addToCart: (item: CartItem) => void;
removeFromCart: (itemId: string, size: string) => void;
calculateTotalPrice: (itemId: string, itemSize: string, itemPrice: number) => number;
updateCartQuantity: (itemId: string, size: string, quantity: number) => void;
syncCartWithBackend: () => Promise;
}
const CartContext = createContext(undefined);
export const CartProvider = ({ children }: { children: ReactNode }) => {
const ls = typeof window !== "undefined" ? window.localStorage : null;
const { data: session, status } = useSession();
const [cart, setCart] = useState([]);
const localStoragekey = "cartItems";
useEffect(() => {
const fetchCart = async () => {
if (status === "authenticated") {
try {
const response = await fetch("/api/cart", { method: "GET" });
if (response.ok) {
const data = await response.json();
//setCart(data.cart);
//syncCartWithBackend();
if(JSON.stringify(data.cart) !== JSON.stringify(cart))
setCart((prevCart) => {
const mergedCart = [...prevCart];
data.cart.forEach((item: CartItem) => {
const existingItem = mergedCart.find(
(cartItem) => cartItem._id === item._id && cartItem.size === item.size
);
if (existingItem) {
// update quantity if item exist in cart
existingItem.quantity += item.quantity;
} else {
mergedCart.push(item);
}
});
return mergedCart;
});
} else {
console.error("Failed to fetch cart from backend:",response.status );
}
} catch (error) {
console.error("Failed to fetch cart from backend:", error);
}
} else if (ls) {
const storedCart = ls.getItem(localStoragekey);
if (storedCart) {
setCart(JSON.parse(storedCart));
}
}
};
if (status === "authenticated" || status === "unauthenticated") {
fetchCart();
}
}, [status]);
// sync after cart is updated
useEffect(() => {
if (status === "unauthenticated" && ls) {
const storedCart = ls.getItem(localStoragekey);
if (storedCart !== JSON.stringify(cart)) {
ls.setItem(localStoragekey, JSON.stringify(cart));
}
}
}, [cart, status, ls]);
// Automatically sync with backend with useeffect and we dont need to call the method in every function
useEffect(() => {
let isSyncing = false;
const syncCartWithBackend = async () => {
if (status === "authenticated" && session?.user?.id && !isSyncing) {
isSyncing = true;
try {
const response = await fetch("/api/cart", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: session.user.id, cartItems: cart }),
});
if (!response.ok) {
console.error("Failed to sync cart with backend:", response.status);
}
} catch (error) {
console.error("Error syncing cart:", error);
} finally {
isSyncing = false;
}
}
};
if(status === "authenticated") {
syncCartWithBackend();
}
}, [cart, status, session]);
const addToCart = (item: CartItem) => {
setCart((prevCart) => {
const existingItem = prevCart.find(
(cartItem) => cartItem._id === item._id && cartItem.size === item.size
);
if (existingItem) {
//update quantity if item is already in cart with same size
return prevCart.map((cartItem) =>
cartItem._id === item._id && cartItem.size === item.size
? { ...cartItem, quantity: Math.max(1,cartItem.quantity + 1) } // prevent quantity being below 1
: cartItem
);
} else {
//add new item to cart
return [...prevCart, { ...item, quantity: 1 }];
}
});
};
const removeFromCart = (itemId: string, size: string) => {
setCart((prevCart) =>
prevCart.filter(
(cartItem) => !(cartItem._id === itemId && cartItem.size === size)
)
);
};
const updateCartQuantity = (
itemId: string,
size: string,
quantity: number
) => {
setCart((prevCart) =>
prevCart
.map((cartItem) =>
cartItem._id === itemId && cartItem.size === size
? {
...cartItem,
quantity: Math.max(0, cartItem.quantity + quantity),
}
: cartItem
)
.filter((cartItem) => cartItem.quantity > 0)
);
};
const calculateTotalPrice = (
itemId: string,
itemSize: string | undefined,
itemPrice: number
) => {
const totalQuantity = cart
.filter((item) => item._id === itemId && item.size === itemSize || item.size === "onesize")
.reduce((acc, item) => acc + item.quantity, 0);
return totalQuantity * itemPrice;
};
return (
{},
}}
>
{children}
);
};
//Function to use the cart
export const useCart = () => {
const context = useContext(CartContext);
if (!context) {
throw new Error();
}
return context;
};
Подробнее здесь: https://stackoverflow.com/questions/794 ... -logged-in
Next.js Cart Duplicates Products при входе в систему ⇐ Javascript
Форум по Javascript
-
Anonymous
1739478228
Anonymous
Я строю веб-сайт электронной коммерции, используя Next.js, TypeScript, MongoDB и NextAuth.js. Я по-разному обращаюсь к корзине для покупок для гостевых пользователей и входа в систему: < /p>
Гостевые пользователи: CAR Пользовательский документ MongoDB. Этого не происходит для гостевых пользователей (Cart LocalStorage работает нормально). < /P>
Как это исправить? Похоже, что код в Cartcontext может быть причиной при попытке объединить корзину. < /P>
cartcontext: < /p>
"use client";
// Good way to manage global state(especially where you need access to multiple components)
import React, {
createContext,
useContext,
useState,
ReactNode,
useEffect,
} from "react";
import { useSession } from "next-auth/react";
export interface CartItem {
_id: string;
name: string;
image: string;
price: number;
size?: string;
quantity: number;
}
// functions go here
interface CartContextType {
cart: CartItem[];
addToCart: (item: CartItem) => void;
removeFromCart: (itemId: string, size: string) => void;
calculateTotalPrice: (itemId: string, itemSize: string, itemPrice: number) => number;
updateCartQuantity: (itemId: string, size: string, quantity: number) => void;
syncCartWithBackend: () => Promise;
}
const CartContext = createContext(undefined);
export const CartProvider = ({ children }: { children: ReactNode }) => {
const ls = typeof window !== "undefined" ? window.localStorage : null;
const { data: session, status } = useSession();
const [cart, setCart] = useState([]);
const localStoragekey = "cartItems";
useEffect(() => {
const fetchCart = async () => {
if (status === "authenticated") {
try {
const response = await fetch("/api/cart", { method: "GET" });
if (response.ok) {
const data = await response.json();
//setCart(data.cart);
//syncCartWithBackend();
if(JSON.stringify(data.cart) !== JSON.stringify(cart))
setCart((prevCart) => {
const mergedCart = [...prevCart];
data.cart.forEach((item: CartItem) => {
const existingItem = mergedCart.find(
(cartItem) => cartItem._id === item._id && cartItem.size === item.size
);
if (existingItem) {
// update quantity if item exist in cart
existingItem.quantity += item.quantity;
} else {
mergedCart.push(item);
}
});
return mergedCart;
});
} else {
console.error("Failed to fetch cart from backend:",response.status );
}
} catch (error) {
console.error("Failed to fetch cart from backend:", error);
}
} else if (ls) {
const storedCart = ls.getItem(localStoragekey);
if (storedCart) {
setCart(JSON.parse(storedCart));
}
}
};
if (status === "authenticated" || status === "unauthenticated") {
fetchCart();
}
}, [status]);
// sync after cart is updated
useEffect(() => {
if (status === "unauthenticated" && ls) {
const storedCart = ls.getItem(localStoragekey);
if (storedCart !== JSON.stringify(cart)) {
ls.setItem(localStoragekey, JSON.stringify(cart));
}
}
}, [cart, status, ls]);
// Automatically sync with backend with useeffect and we dont need to call the method in every function
useEffect(() => {
let isSyncing = false;
const syncCartWithBackend = async () => {
if (status === "authenticated" && session?.user?.id && !isSyncing) {
isSyncing = true;
try {
const response = await fetch("/api/cart", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: session.user.id, cartItems: cart }),
});
if (!response.ok) {
console.error("Failed to sync cart with backend:", response.status);
}
} catch (error) {
console.error("Error syncing cart:", error);
} finally {
isSyncing = false;
}
}
};
if(status === "authenticated") {
syncCartWithBackend();
}
}, [cart, status, session]);
const addToCart = (item: CartItem) => {
setCart((prevCart) => {
const existingItem = prevCart.find(
(cartItem) => cartItem._id === item._id && cartItem.size === item.size
);
if (existingItem) {
//update quantity if item is already in cart with same size
return prevCart.map((cartItem) =>
cartItem._id === item._id && cartItem.size === item.size
? { ...cartItem, quantity: Math.max(1,cartItem.quantity + 1) } // prevent quantity being below 1
: cartItem
);
} else {
//add new item to cart
return [...prevCart, { ...item, quantity: 1 }];
}
});
};
const removeFromCart = (itemId: string, size: string) => {
setCart((prevCart) =>
prevCart.filter(
(cartItem) => !(cartItem._id === itemId && cartItem.size === size)
)
);
};
const updateCartQuantity = (
itemId: string,
size: string,
quantity: number
) => {
setCart((prevCart) =>
prevCart
.map((cartItem) =>
cartItem._id === itemId && cartItem.size === size
? {
...cartItem,
quantity: Math.max(0, cartItem.quantity + quantity),
}
: cartItem
)
.filter((cartItem) => cartItem.quantity > 0)
);
};
const calculateTotalPrice = (
itemId: string,
itemSize: string | undefined,
itemPrice: number
) => {
const totalQuantity = cart
.filter((item) => item._id === itemId && item.size === itemSize || item.size === "onesize")
.reduce((acc, item) => acc + item.quantity, 0);
return totalQuantity * itemPrice;
};
return (
{},
}}
>
{children}
);
};
//Function to use the cart
export const useCart = () => {
const context = useContext(CartContext);
if (!context) {
throw new Error();
}
return context;
};
Подробнее здесь: [url]https://stackoverflow.com/questions/79437635/next-js-cart-duplicates-products-when-logged-in[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия