我正在尝试使用我创建的上下文来创建一个非常简单的购物车示例,为此,我创建了一些函数,当我尝试在组件内部使用它时,会弹出错误。
在使用 Context API 方面,我实际上是一个初学者,所以如果有人可以提供帮助,我会非常高兴。
这是我的背景
"use client";
import { createContext, useState, ReactNode } from "react";
import { ShoppingCartProviderProps } from "../types/ShoppingCartProvider";
import { ShoppingCartFunction } from "../types/ShoppingCartFunction";
import { ProductCartItem } from '../types/Product';
export const ShoppingCartContext = createContext({} as ShoppingCartFunction);
export function ShoppingCartProvider({ children }: ShoppingCartProviderProps) {
const [cartItem, setCartItem] = useState<ProductCartItem[]>([]);
function getItemQuantity(id: number) {
return cartItem.find(item => item.id === id)?.quantity || 0;
}
function increaseItemQuantity(id: number) {
setCartItem(currItems => {
if (currItems.find(item => item.id === id) == null) {
return [...currItems, { id, quantity: 1 }];
} else {
return currItems.map(item => {
if (item.id === id) {
return { ...item, quantity: item.quantity + 1 };
} else {
return item;
}
});
}
});
}
function decreaseItemQuantity(id: number) {
setCartItem(currItems => {
if (currItems.find(item => item.id === id)?.quantity === 1) {
return currItems.filter(item => item.id !== id);
} else {
return currItems.map(item => {
if (item.id === id) {
return { ...item, quantity: item.quantity - 1 };
} else {
return item;
}
});
}
});
}
function removeFromCart(id: number) {
setCartItem(currentItems => {
return currentItems.filter(item => item.id !== id);
});
}
return (
<ShoppingCartContext.Provider value={{ getItemQuantity, increaseItemQuantity, decreaseItemQuantity, removeFromCart }}>
{children}
</ShoppingCartContext.Provider>
);
}
我如何从 API 获取数据:
export const getData = async () => {
const res = await fetch('https://fakestoreapi.com/products?limit=5');
if (!res.ok) {
throw new Error();
}
return res.json();
};
以及我尝试在上下文中渲染的组件
import { ShoppingCartContext } from "@/app/context/ShoppingCartContext";
import { getData } from "@/app/data/fetchData";
import { ProductCardDescType } from "@/app/types/Product";
import ProductCard from "@/components/ProductCard/ProductCard";
import { useContext } from "react";
export default async function Store() {
const post = await getData();
const { getItemQuantity } = useContext(ShoppingCartContext)
return (
<div>
<h1>Store</h1>
{post.map((product: ProductCardDescType) => (
<ProductCard key={product.id} {...product} />
))}
</div>
);
}
提供者:
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import NavBar from "@/components/NavBar/NavBar";
import { ShoppingCartProvider } from "./context/ShoppingCartContext";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>
<ShoppingCartProvider>
<NavBar/>
{children}
</ShoppingCartProvider>
</body>
</html>
);
}
我想在组件内使用它的上下文,然后使用我为其创建的其他函数。
看起来像是客户端与服务器组件问题。
这里有一个链接,next.js 文档明确指出:
由于服务器组件不支持 React 上下文,...
简短的版本是,您正在尝试将“客户端”代码导入到服务器组件中。
具体来说这一行:
const { getItemQuantity } = useContext(ShoppingCartContext)
要解决此问题,您需要:
使用“useContext”和“use client”标记组件,从而改变您调用的方式
const post = await getData()
,因为它不是服务器组件
使服务器组件导入一些包装您的提供程序的客户端组件。 由于
ClientComponent
可以使用“useContext”,因此您可以在该 comoent 中渲染所需内容并将相关数据传递到服务器组件。
import ClientComponent from './client-component'
import ServerComponent from './server-component'
// Pages in Next.js are Server Components by default
export default function Page() {
return (
<ClientComponent>
<ServerComponent />
</ClientComponent>
)
}
要记住的重要一点是,服务器组件是在服务器上渲染的,因此它们没有交互生命周期效果(useState()、useReducer()、useEffect() 等)