Using Redux with Next.js 13 App Router
With the new Next.js 13 App Router, Next.js has made all components server components by default. This changes a lot of things and introduces different ways of doing things — and one of the things that needs slight modification is the way we define and use Redux.
Creating and providing the store
The differences from the old pages router come down to one fact:
All components are server components by default
Since all components are server components by default, we cannot use state-related hooks in them. To use such features, a component must become a client component by putting 'use client' at the top of the file. And there's no _app.js to wrap with <Provider> anymore — the App Router gives us layout.js for that job.
Bad approach
One way is to simply put 'use client' at the top of the root layout.js and provide the store there — but this makes every child component a client component, and we lose the benefits of server components entirely.
Good approach
- Create a custom provider component marked 'use client'.
- Wrap it around the children in layout.js.
- Provide the store inside the provider component.
- Return the {children} passed into it.
layout.js
import ReduxProvider from "./ReduxProvider";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<ReduxProvider>{children}</ReduxProvider>
</body>
</html>
);
}ReduxProvider.js
"use client";
import { Provider } from "react-redux";
import { store } from "./store";
export default function ReduxProvider({ children }) {
return <Provider store={store}>{children}</Provider>;
}This way the provider itself is a client component, but everything it wraps stays server-renderable.
Using Redux: patterns
Redux lives on the client side, so components that consume it must be client components. Next.js provides a few patterns to keep the app optimized when mixing server and client components.
Move client components to the leaves
Push client components — anything interactive, anything using Redux — as far down the tree as possible. This ensures the maximum number of components stay server-rendered.
Pass server components as props
Sometimes an interactive client component needs to show data fetched in a server component. Importing a server component inside a client component is an antipattern — it forces another round trip to render the nested component. The supported pattern is to pass the server component as a prop (typically children) to the client component from a shared parent.
Following these patterns keeps the app optimized and the user experience fast.
Originally published on LinkedIn.