From 42620c24700ce21a45ca8f64c64eb85b020a8b32 Mon Sep 17 00:00:00 2001 From: jy95 Date: Sun, 1 Dec 2024 12:44:04 +0100 Subject: [PATCH] refactor: migrate redux code to be compliant with next.js --- src/app/[locale]/layout.tsx | 6 +-- src/providers/StoreProvider.tsx | 18 +++++++++ src/redux/Store.tsx | 69 +++++++++++++++++---------------- src/redux/hooks.ts | 10 +++-- src/redux/provider.tsx | 8 ---- 5 files changed, 63 insertions(+), 48 deletions(-) create mode 100644 src/providers/StoreProvider.tsx delete mode 100644 src/redux/provider.tsx diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx index b8459b5b..1962d015 100644 --- a/src/app/[locale]/layout.tsx +++ b/src/app/[locale]/layout.tsx @@ -1,6 +1,6 @@ // Providers -import { Providers as ReduxProviders } from "@/redux/provider"; import { ThemeProvider } from "@/providers/ThemeProvider"; +import StoreProvider from "@/providers/StoreProvider"; // Next.js Analytics import { SpeedInsights } from '@vercel/speed-insights/next'; @@ -57,7 +57,7 @@ export default async function RootLayout(props: Props) { return ( - + @@ -80,7 +80,7 @@ export default async function RootLayout(props: Props) { - + diff --git a/src/providers/StoreProvider.tsx b/src/providers/StoreProvider.tsx new file mode 100644 index 00000000..4b7c7ea4 --- /dev/null +++ b/src/providers/StoreProvider.tsx @@ -0,0 +1,18 @@ +'use client' +import { useRef } from 'react' +import { Provider } from 'react-redux' +import { makeStore, AppStore } from '../redux/Store' + +export default function StoreProvider({ + children, +}: { + children: React.ReactNode +}) { + const storeRef = useRef(null) + if (!storeRef.current) { + // Create the store instance the first time this renders + storeRef.current = makeStore() + } + + return {children} +} \ No newline at end of file diff --git a/src/redux/Store.tsx b/src/redux/Store.tsx index 8c71e068..5656a8f7 100644 --- a/src/redux/Store.tsx +++ b/src/redux/Store.tsx @@ -11,37 +11,40 @@ import { platformsAPI } from "./services/platformsAPI" import { genresAPI } from "./services/genresAPI"; import { dlcsAPI } from "./services/dlcsAPI"; -/* eslint-disable no-underscore-dangle */ -const store = configureStore({ - reducer: { - // common reducers - games, - // API calls - [gamesAPI.reducerPath]: gamesAPI.reducer, - [planningAPI.reducerPath]: planningAPI.reducer, - [seriesAPI.reducerPath]: seriesAPI.reducer, - [statsAPI.reducerPath]: statsAPI.reducer, - [testsAPI.reducerPath]: testsAPI.reducer, - [backlogAPI.reducerPath]: backlogAPI.reducer, - [platformsAPI.reducerPath]: platformsAPI.reducer, - [genresAPI.reducerPath]: genresAPI.reducer, - [dlcsAPI.reducerPath]: dlcsAPI.reducer - }, - // Adding the api middleware enables caching, invalidation, polling, - // and other useful features of `rtk-query`. - middleware: (getDefaultMiddleware) => getDefaultMiddleware() - .concat(gamesAPI.middleware) - .concat(planningAPI.middleware) - .concat(seriesAPI.middleware) - .concat(statsAPI.middleware) - .concat(testsAPI.middleware) - .concat(backlogAPI.middleware) - .concat(platformsAPI.middleware) - .concat(genresAPI.middleware) - .concat(dlcsAPI.middleware), -}) -export default store; +export const makeStore = () => { + return configureStore({ + reducer: { + // common reducers + games, + // API calls + [gamesAPI.reducerPath]: gamesAPI.reducer, + [planningAPI.reducerPath]: planningAPI.reducer, + [seriesAPI.reducerPath]: seriesAPI.reducer, + [statsAPI.reducerPath]: statsAPI.reducer, + [testsAPI.reducerPath]: testsAPI.reducer, + [backlogAPI.reducerPath]: backlogAPI.reducer, + [platformsAPI.reducerPath]: platformsAPI.reducer, + [genresAPI.reducerPath]: genresAPI.reducer, + [dlcsAPI.reducerPath]: dlcsAPI.reducer + }, + // Adding the api middleware enables caching, invalidation, polling, + // and other useful features of `rtk-query`. + middleware: (getDefaultMiddleware) => getDefaultMiddleware() + .concat(gamesAPI.middleware) + .concat(planningAPI.middleware) + .concat(seriesAPI.middleware) + .concat(statsAPI.middleware) + .concat(testsAPI.middleware) + .concat(backlogAPI.middleware) + .concat(platformsAPI.middleware) + .concat(genresAPI.middleware) + .concat(dlcsAPI.middleware), + }); +} + +// Infer the type of makeStore +export type AppStore = ReturnType + // Infer the `RootState` and `AppDispatch` types from the store itself -export type RootState = ReturnType -// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState} -export type AppDispatch = typeof store.dispatch \ No newline at end of file +export type RootState = ReturnType +export type AppDispatch = AppStore['dispatch'] \ No newline at end of file diff --git a/src/redux/hooks.ts b/src/redux/hooks.ts index a545058a..71c442c1 100644 --- a/src/redux/hooks.ts +++ b/src/redux/hooks.ts @@ -1,5 +1,7 @@ -import { useDispatch, useSelector } from "react-redux"; -import type { RootState, AppDispatch } from "./Store"; +import { useDispatch, useSelector, useStore } from "react-redux"; +import type { RootState, AppDispatch, AppStore } from './Store' -export const useAppDispatch = useDispatch.withTypes(); -export const useAppSelector = useSelector.withTypes(); \ No newline at end of file +// Use throughout your app instead of plain `useDispatch` and `useSelector` +export const useAppDispatch = useDispatch.withTypes() +export const useAppSelector = useSelector.withTypes() +export const useAppStore = useStore.withTypes() \ No newline at end of file diff --git a/src/redux/provider.tsx b/src/redux/provider.tsx deleted file mode 100644 index e49209f2..00000000 --- a/src/redux/provider.tsx +++ /dev/null @@ -1,8 +0,0 @@ -"use client"; - -import store from "./Store"; -import { Provider } from "react-redux"; - -export function Providers({ children }: { children: React.ReactNode }) { - return {children}; -}