错误:找不到 react-redux 上下文值;请确保在使用 useselector 时组件被包装在 <Provider> 中
1.header.js
import Image from "next/image";
import {
MenuIcon,
SearchIcon,
ShoppingCartIcon,
} from "@heroicons/react/outline";
import { signIn, signOut, useSession } from "next-auth/react";
import { useRouter } from "next/router";
import { useSelector } from "react-redux";
import { selectItems } from "../slices/basketSlice";
import { Provider } from "react-redux";
function Header() {
const { data: session } = useSession();
const router = useRouter();
const items= useSelector(selectItems);
return (
<header>
<div className="flex items-center bg-amazon_blue p-1 flex-grow py-2">
<div className="mt-2 flex items-center flex-grow sm:flex-grow-0">
<Image
onClick={() => router.push("/")}
src='https://links.papareact.com/f90'
width={150}
height={40}
objectFit="contain"
className="cursor-pointer"
/>
</div>
{/*search bar*/}
<div className="hidden sm:flex items-center h-10 rounded-md flex-grow cursor-pointer bg-yellow-400 hover:bg-yellow-500">
<input className="p-2 h-full w-6 flex-grow flex-shrink rounded-l-md focus:outline-none px-4" type="text" />
<SearchIcon className="h-12 p-4"/>
</div>
<div className="text-white flex items-center text-xs space-x-6 mx-6 whitespace-nowrap">
<div onClick={session ? signIn:signOut} className="link">
<p className="hover:underline">{session ? session.user.name:"signin"}</p>
<p className="font-extrabold md:text-sm">Acount & lists</p>
</div>
<div className=" link">
<p>Returns</p>
<p className="font-extrabold md:text-sm">& orders</p>
</div>
<div onClick={() => router.push("/checkout")} className=" link relative flex items-center">
<span className="absolute top-0 right-0 md:right-10 h-4 w-4 bg-yellow-400 rounded-full text-center text-black font-bold">
{items.length}
</span>
<ShoppingCartIcon className="h-10 "/>
<p className="hidden md:inline font-extrabold md:text-sm mt-2">Bascket</p>
</div>
</div>
</div>
{/*bottom nav*/}
<div className="flex items-center space-x-3 p-2 pl-6 bg-amazon_blue-light text-white text-sm">
<p className="link flex items-center ">
<MenuIcon className="h-6 mr-5"/>
all</p>
<p className="link">featured </p>
<p className="link">new arrival </p>
<p className="link">catalog </p>
<p className="link hidden lg-inline-flex">electronics </p>
</div>
</header>
);
}
export default Header;
- bascketslice.js
'''
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
items: [],
};
export const basketSlice = createSlice({
name: "basket",
initialState,
reducers: {
addToBasket: (state, action) => {
state.items = [...state.items, action.payload]
},
removeFromBasket: (state, action) => {},
},
});
export const { addToBasket, removeFromBasket } = basketSlice.actions;
// Selectors - This is how we pull information from the Global store slice
export const selectItems = (state) => state.basket.items;
export default basketSlice.reducer;
'''
-
product.js
'''
从“next/image”导入图片; 从“react”导入{useState}; 从“@heroicons/react/solid”导入{StarIcon}; 从“react-currency-format”导入货币; 从“react-redux”导入{useDispatch}; 从“../slices/basketSlice”导入{addToBasket};
const MAX_RATING =5; const MIN_RATING =1;
function Product({id, title, price, description, category,image}) { const dispatch = useDispatch(); const{rating}= useState( Math.floor(Math.random() * (MAX_RATING - MIN_RATING +1)) + MIN_RATING ); const addItemToBascket = () => { const product = {id, title, price, description, category,image}; // 将产品作为操作发送到 bascket 切片 dispatch(addToBasket(product)) };
return ( {category}
<Image src={image} height={200} width={200} objectFit="contain" /> <h4 className="flex">{title}</h4> <div className="flex"> {Array(rating) .fill() .map((_, i)=>( <StarIcon className="h-5 text-yellow-500"/> ))} </div> <p className="text-xs my-2 line-clamp-2">{description}</p> <div className="mb-5"> <Currency quant={price}/> </div> <button onClick={addItemToBascket} className=" mt-auto button">添加到购物篮</button> </div>
);
导出默认产品 '''
store.js
import { configureStore } from "@reduxjs/toolkit";
import basketReducer from "../slices/basketSlice";
export const store = configureStore({
reducer: {
basket: basketReducer,
},
});
_app.js
import { Provider } from 'react-redux'
import { store } from '../app/store'
import '../styles/globals.css'
import { SessionProvider } from "next-auth/react"
const MyApp = ({ Component, pageProps: {session,...pageProps} }) => {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
);
};
export default MyApp
如何在代码中使用提供程序
看来我们都是桑尼的粉丝。您的问题是您需要将 App.js 包装在
<Provider>
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
</Provider>
但是您很可能会遇到“Hydration 错误”,如果是这样,只需删除
“Math.floor(Math.random() * (MAX_RATING - MIN_RATING +1)) + MIN_RATING”
显然,随着新的更新,我们不能再像以前那样使用 useState() 钩子了,所以您有 3 个选项:
1.- 删除
“Math.floor(Math.random() * (MAX_RATING - MIN_RATING +1)) + MIN_RATING”
2.- 为所有产品设置固定评级
3.- 为您的 API 设置一个数字(您不能这样做,因为您使用的是 FakeStoreAPI)
这是由于 Hooks 的基本规则,因为随机数是“不可预测的”,但现在我不知道为什么会出现这个问题(尽管你设置了最小值和最大值)