I followed the official docs in how to make the redux work with Next.js app router. Everything worked as expected, but now I am trying to persist the data with redux-persist and things got very muddy.
There is no example in the official redux docs. I don't know how to deal with the fact that I am creating a Redux store per request by using configureStore wrapped in a makeStore function (recommended approach by official Redux docs to use Redux with Next app router).
I can't even pass makeStore to the persistStore method without getting type errors:
Argument of type '() => EnhancedStore<{ user: userInterface; } & PersistPartial, UnknownAction, Tuple<[StoreEnhancer<{ dispatch: ThunkDispatch<{ user: userInterface; } & PersistPartial, undefined, UnknownAction>; }>, StoreEnhancer]>>' is not assignable to parameter of type 'Store<any, UnknownAction, unknown>'
This is where I am currently at:
store.js:
import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import { configureStore, combineReducers } from '@reduxjs/toolkit'
import {userReducer} from "./user/userSlice"
const combinedReducers = combineReducers({
user: userReducer,
})
const persistedReducer = persistReducer(
{
key: 'root',
storage,
whitelist: ['user'],
},
combinedReducers
)
export const makeStore = () => {
return configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}),
})
}
export const persistor = persistStore(makeStore)
export type AppStore = ReturnType<typeof makeStore>
export type RootState = ReturnType<AppStore['getState']>
export type AppDispatch = AppStore['dispatch']
store provider:
"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<AppStore>();
if (!storeRef.current) {
// Create the store instance the first time this renders
storeRef.current = makeStore();
}
return <Provider store={storeRef.current}>{children}</Provider>;
}
layout.js
import type { Metadata } from "next";
import "./globals.css";
import StoreProvider from "./StoreProvider";
export const metadata: Metadata = {
title: "App",
description: "App Desription",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<StoreProvider>{children}</StoreProvider>
</body>
</html>
);
}
How can I adapt the code to persist the Redux data considering the necessity of creating the store per request?
Below is my implentation of the
store.tsWe need to know of the server and client mode in Next.js because we don't eventually need persistence on the server side.
Below is my implementation of
StoreProvider.tsxUsing ref to maintain the
storestate between renders, you can then wrap your whole app with thisStateProvidercomponent.A huge shout-out to this blog here for making it look easier.