Package for setting up Redux with Next.js with ease.
This package is inspired by next-redux-wrapper but with a few key features in mind:
- 🔥 super easy to setup
- 📦 very lightweight
Sometimes you might want to fetch data in your Next.js application server-side using one of Next's data fetching methods (
getInitialProps
,getServerSideProps
orgetStaticProps
). By doing that you also might want to preload that fetched data server-side directly to your Redux store. This package makes it super easy to do exactly that!
You will have a server side instance of your Redux store on which you can dispatch actions. Redux's job on the server side is to provide the initial state of our app. That server side store will than be passed to the client side and will hydrate the client side store with your server side data - all that without a delay or flicker on the UI which usually occurs if you are hydrating your client side store by dispatching an action in useEffect hook.
yarn add @fifi98/next-redux react-redux
First create your Redux store, for example in store.ts
file.
import { AnyAction, combineReducers, configureStore } from "@reduxjs/toolkit";
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import { HYDRATE } from "@fifi98/next-redux";
import facts from "./facts";
const combinedReducer = combineReducers({ facts });
const reducer = (state: ReturnType<typeof combinedReducer> | undefined, action: AnyAction): ReturnType<typeof combinedReducer> => {
if (action.type === HYDRATE) {
return { ...state, ...action.payload };
} else {
return combinedReducer(state, action);
}
};
export const store = configureStore({ reducer });
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
The next step is to wrap your _app.tsx
with the StoreProvider
component which accepts two props - store
which we created in the previous step and state
- the data which is going to be passed from your server side data fetching methods.
import { store } from "../store";
import { StoreProvider } from "@fifi98/next-redux";
function MyApp({ Component, pageProps }: AppProps) {
return (
<StoreProvider store={store} state={pageProps.state}>
<Component {...pageProps} />
</StoreProvider>
);
}
import { createStore } from "@fifi98/next-redux";
MyApp.getInitialProps = async (): Promise<AppInitialProps> => {
const { getState, dispatch } = createStore(store);
const data = await fetch("https://catfact.ninja/fact").then((r) => r.json());
dispatch(setFact(data.fact));
return {
pageProps: {
state: getState(),
},
};
};
import { createStore } from "@fifi98/next-redux";
export const getServerSideProps: GetServerSideProps = async () => {
const { getState, dispatch } = createStore(store);
const data = await fetch("https://catfact.ninja/fact").then((r) => r.json());
dispatch(setFact(data.fact));
return {
props: {
state: getState(),
},
};
};
import { createStore } from "@fifi98/next-redux";
export const getStaticProps: GetStaticProps = async () => {
const { getState, dispatch } = createStore(store);
const data = await fetch("https://catfact.ninja/fact").then((r) => r.json());
dispatch(setFact(data.fact));
return {
props: {
state: getState(),
},
};
};
The demo app is available in the demo
folder