开发者问题收集

错误:找不到 react-redux 上下文值;请确保在使用 useselector 时组件被包装在 <Provider> 中

2022-03-24
926

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;
  1. 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;

'''

  1. 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

files in my code

如何在代码中使用提供程序

我的存储库:- https://github.com/Shadow2389/nmz-2.git

1个回答

看来我们都是桑尼的粉丝。您的问题是您需要将 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 的基本规则,因为随机数是“不可预测的”,但现在我不知道为什么会出现这个问题(尽管你设置了最小值和最大值)

Omar Nasser Serrano Martínez
2022-06-24