reduxjs/redux-toolkit

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

smile6065 opened this issue · 1 comments

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!