reduxjs / redux-toolkit

The official, opinionated, batteries-included toolset for efficient Redux development
https://redux-toolkit.js.org
MIT License
10.69k stars 1.16k forks source link

Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider> #4410

Closed smile6065 closed 1 week ago

smile6065 commented 4 months ago

I'm having some problems learning Redux, and I'm currently using React 18 + Next 14 + Typescript + App Router.

When I integrate as per the development documentation, it always prompts me for this error, even if I copy the code in the example.

// store.ts
import { configureStore } from "@reduxjs/toolkit";
import demoReducer from "./features/demo/demoSlice";
export const makeStore: any = () => {
    return configureStore({
        reducer: {
            demo: demoReducer,
        },
    });
};

export type AppStore = ReturnType<typeof makeStore>;
export type RootState = ReturnType<AppStore["getState"]>;
export type AppDispatch = AppStore["dispatch"];
// hooks.ts
import { useDispatch, useSelector, useStore } from "react-redux";
import type { AppStore, AppDispatch, RootState } from "./store";

export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
export const useAppSelector = useSelector.withTypes<RootState>();
export const useAppStore = useStore.withTypes<AppStore>();
// demoSlice.ts
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import type { RootState } from "../../store";

const initialState = {
    value: 0,
};

export const demoSlice = createSlice({
    name: "demo",
    initialState,
    reducers: {
        increment: (state) => {
            state.value += 1;
        },
        decrement: (state) => {
            state.value -= 1;
        },
        incrementByAmount: (state, action: PayloadAction<number>) => {
            state.value += action.payload;
        },
        initializeCount: (state, action: PayloadAction<number>) => {
            state.value = action.payload || 0;
        },
    },
});

export const { increment, decrement, incrementByAmount, initializeCount } = demoSlice.actions;

export const selectCount = (state: RootState) => state.demo.value;

export default demoSlice.reducer;
// StoreProvider.tsx
"use client";
import { useRef } from "react";
import { Provider } from "react-redux";
import { makeStore, AppStore } from "./services/stores/store";

import { initializeCount } from "./services/stores/features/demo/demoSlice";

export default function StoreProvider({
    data,
    children,
}: {
    data: any;
    children: React.ReactNode;
}) {
    const storeRef = useRef<AppStore | null>(null);
    if (!storeRef.current) {
        storeRef.current = makeStore();
        storeRef.current.dispatch(initializeCount(data));
    }

    return <Provider store={storeRef.current}>{children}</Provider>;
}
// OpenMenuButton.tsx
"use client";
import { useRef } from "react";
import {
    useAppSelector,
    useAppDispatch,
    useAppStore,
} from "@services/stores/hooks";
import {
    increment,
    decrement,
    incrementByAmount,
    initializeCount,
} from "@/app/services/stores/features/demo/demoSlice";

export default function OpenMenuButton() {
    const store = useAppStore();
    const initialized = useRef(false);

    if (!initialized.current) {
        store.dispatch(initializeCount(0));
        initialized.current = true;
    }

    const count = useAppSelector((state) => {
        console.log(state.demo.value);
        return state.demo.value;
    });
    const dispatch = useAppDispatch();

    return (
        <div>
            <div>
                <button onClick={() => dispatch(increment())}>Increment</button>
                <span>{count}</span>
                <button onClick={() => dispatch(decrement())}>Decrement</button>
            </div>
        </div>
    );
}

image

Thank you!

gantavya99 commented 4 months ago

I think you need to wrap your jsx with the context provider as mentioned in the error above. image Try wrapping your jsx with the Provider provided by react-redux along with the store prop. Let me know if this helps, or if I am missing something.