Redux is one of the most popular state management solutions in the React ecosystem. Nowadays, there are plenty of alternatives, but Redux is still the most trusted and widely used tool.
For this reason, many projects that use Next.js want to take advantage of Redux as well. But using Redux in a Next application has a few catches, and the setup is not always straightforward. That’s why this article will walk you through how we can set up a Next project with Redux.
Contents
- Why should you use Redux with Next.js?
- Building a sample app with Next.js and Redux
- Using the Redux store
- Persisting the state in Next.js
Why should you use Redux with Next.js?
There are a lot of reasons why you might want to use Redux in a Next application. Let’s take a look at some of them.
Sharing state
Usually, a central state is used to manage the shared data between the components in a tree. In React, data flows only downwards, which means you can pass data from the parent component to a child component.
This limitation sometimes makes things hard, because the components might not be close in the component tree, and there might not even be a parent-child path.
In this case, using a common store that wraps all the components makes total sense, and you might consider Redux.
Redux is very powerful
Redux is very powerful as a state management solution. It’s been around for a while, so it has excellent community support.
If you are building something serious and unsure which use-cases might appear in the future, more likely than not, Redux will have a solution for you. While nothing is completely future-proof, Redux is a safe bet for long-term projects.
Everybody knows Redux
In many projects, speed is often a priority. Many React developers are already familiar with Redux, and companies often want to use the same tool across all of the projects if possible.
This means even if you are working in a company that is building a new project in Next, you might be forced to use Redux anyway, so it’s a good idea to learn how to use it based on popularity alone.
Building a sample app with Next.js and Redux
Today we will build a simple application that tracks if a user is logged in or not, then based on the state, changes the text above the button.
The purpose of this project is to demonstrate how to use Redux, so I am keeping things simple here so that we can focus on the Redux integration with the Next. Going forward, we have two options. We can use plain Redux, or we can use Redux Toolkit.
Redux is being used in many legacy projects, but Redux Toolkit is recommended, as it reduces a lot of boilerplate code and has improved performance. However the setups are almost the same for both of these.
Let’s create the starter project by running the following command:
yarn create next-app --typescript
You can see the project in action by running yarn dev
and visiting http://localhost:3000/ on your browser.
Installing the dependencies
Let’s install the required dependencies for Redux Toolkit:
yarn add @reduxjs/toolkit react-redux
As we are using Next, we will need an additional package to take care of our server-side rendering:
yarn add next-redux-wrapper
Creating the slice
Let’s create a new folder called store
and create a file named authSlice.ts
inside it. The official documentation defines a slice as: “a collection of Redux reducer logic and actions for a single feature in your app.”
We will put the logic for our authState
inside of this authSlice.ts
file:
import { createSlice } from "@reduxjs/toolkit";import { AppState } from "./store";import { HYDRATE } from "next-redux-wrapper";// Type for our stateexport interface AuthState { authState: boolean;}// Initial stateconst initialState: AuthState = { authState: false,};// Actual Sliceexport const authSlice = createSlice({ name: "auth", initialState, reducers: { // Action to set the authentication status setAuthState(state, action) { state.authState = action.payload; }, // Special reducer for hydrating the state. Special case for next-redux-wrapper extraReducers: { [HYDRATE]: (state, action) => { return { ...state, ...action.payload.auth, }; }, }, },});export const { setAuthState } = authSlice.actions;export const selectAuthState = (state: AppState) => state.auth.authState;export default authSlice.reducer;
This is a straightforward slice. A slice for any normal React application using Redux will be just like this. There is nothing special for Next yet.
The only thing we are doing here is defining the authState
in our store and creating the action for setting the authState
named setAuthState
.
In line 27, you will notice there is a special reducer that we are adding here called HYDRATE
. The HYDRATE
action handler must properly reconcile the hydrated state on top of the existing state (if any).
Basically, when any page refresh occurs, if you navigate from one page to another page, or the getStaticProps
or the getServerSideProps
functions are called, a HYDRATE
action will be dispatched at that moment. The payload
of this action will contain the state at the moment of static generation or server-side rendering, so your reducer must merge it with the existing client state properly.
Creating the store
Next, create a file named store.ts
to create the store, and add our authSlice
there:
import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";import { authSlice } from "./authSlice";import { createWrapper } from "next-redux-wrapper";const makeStore = () => configureStore({ reducer: { [authSlice.name]: authSlice.reducer, }, devTools: true, });export type AppStore = ReturnType<typeof makeStore>;export type AppState = ReturnType<AppStore["getState"]>;export type AppThunk<ReturnType = void> = ThunkAction< ReturnType, AppState, unknown, Action>;export const wrapper = createWrapper<AppStore>(makeStore);
Notice on line 22 where we export a special wrapper
function. This wrapper eliminates the need for a Provider
that we would use in a normal React application.
Updating the app
We have to do one last thing to finish setting up our Redux architecture. Open the _app.tsx
file and wrap our component like so:
import "../styles/globals.css";import type { AppProps } from "next/app";import { wrapper } from "../store/store";function MyApp({ Component, pageProps }: AppProps) { return <Component {...pageProps} />;}export default wrapper.withRedux(MyApp);
Notice at line 9 that we are wrapping our component with withRedux
. We can wrap the individual pages as well, but that is not recommended; when we navigate from one page to another, if that particular page is not wrapped, it will crash.
Using the Redux store
Our Redux setup is complete! Let’s use our Redux store inside the index.tsx
page like so:
import type { NextPage } from "next";import { selectAuthState, setAuthState } from "../store/authSlice";import { useDispatch, useSelector } from "react-redux";const Home: NextPage = () => { const authState = useSelector(selectAuthState); const dispatch = useDispatch(); return ( <div> <div>{authState ? "Logged in" : "Not Logged In"}</div> <button onClick={() => authState ? dispatch(setAuthState(false)) : dispatch(setAuthState(true)) } > {authState ? "Logout" : "LogIn"} </button> </div> );};export default Home;
Any Redux store has two main purposes: reading and updating.
On line 6, you can see we are reading the state using the useSelector
function provided by react-redux
.
More great articles from LogRocket:
- Don't miss a moment with The Replay, a curated newsletter from LogRocket
- Learn how LogRocket's Galileo cuts through the noise to proactively resolve issues in your app
- Use React's useEffect to optimize your application's performance
- Switch between multiple versions of Node
- Discover how to animate your React app with AnimXYZ
- Explore Tauri, a new framework for building binaries
- Compare NestJS vs. Express.js
We have a button where we can toggle the authState
, and based on this, we are changing the text on the button.
Persisting the state in Next.js
Now we have successfully set up our Redux store. You can verify it by clicking the button, which will dispatch actions based on the current state and update the store, which will eventually change the state.
But if you refresh your page, you will see that the state doesn’t persist. This is because in Next, each page is rendered on demand, which means when you navigate from one page to another, the previous state will be gone.
For this case, if the user is logged in, then whenever you switch to another page, the user will be logged out automatically as the initial authState
is defined as false.
To resolve this issue, we will take advantage of the wrapper function that we created earlier and use Next’s special function getServerSideProps
, as this will get called each time the page loads.
Let’s add the following code into our index.tsx
file:
export const getServerSideProps = wrapper.getServerSideProps( (store) => async ({ params }) => { // we can set the initial state from here // we are setting to false but you can run your custom logic here await store.dispatch(setAuthState(false)); console.log("State on server", store.getState()); return { props: { authState: false, }, }; });
We are generating the initial state inside the getServerSideProps
function here so even if you refresh the page you will see that the state values remain the same.
Conclusion
That’s how you can integrate Redux with a Next application! You can find the GitHub repository for this project here. I would also encourage you to review the documentation of next-redux-wrapper to learn more about other use cases.
Have a great day!
LogRocket: Full visibility into production Next.js apps
Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your Next.js app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.
The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.
Modernize how you debug your Next.js apps — start monitoring for free.
FAQs
Is it okay to use Redux with Nextjs? ›
Can I use Next. js with Redux? Yes! Here's an example with Redux and an example with thunk.
How to integrate redux in next js? ›- Step 1: Project set-up in Next. ...
- Step 2: Installing dependencies. ...
- Step 3: Creating actions. ...
- Step 4: Creating reducers: ...
- Step 5: Initializing the Redux store for application-wide use. ...
- Step 6: GET request to fetch footballers' data from our API:
- npm install next-redux-wrapper react-redux --save.
- import React from 'react'; import {wrapper} from '../components/store'; import {AppProps} from 'next/app'; class MyApp extends React. ...
- class Page extends Component { public static getInitialProps = wrapper.
As a rule of thumb - and one shared by one of Redux's creators, Dan Abramov - you don't need to use Redux unless you're unable to manage state within React or other front-end frameworks you're working with.
What is the drawback of Redux? ›Lack of Encapsulation
There is no possibility of encapsulating any data in the Redux library. So, the chances of security issues grow as an application becomes heavier with new components. Since there is no data encapsulation, any component can access it.
- Set up next-redux-wrapper.
- In getStaticProps or getServerSideProps : Pre-fetch all queries via the initiate actions, e.g. store. dispatch(api. endpoints. ...
- In your createApi call, configure rehydration using the extractRehydrationInfo option: TypeScript. JavaScript.
js, MobX, Flux, React, and RxJS are the most popular alternatives and competitors to Redux.
Is Redux relevant in 2022? ›Redux makes the state predictable In Redux, the state is always predictable. If the same state and action move to a reducer, it will obtain the same result because reducers are pure functions. The state is also immutable and is never changed. It makes it possible to implement arduous tasks like infinite undo and redo.
When should I use Redux? ›- You have large amounts of application state that are needed in many places in the app.
- The app state is updated frequently.
- The logic to update that state may be complex.
- The app has a medium or large-sized codebase, and might be worked on by many people.
Redux definitely isn't required for small projects. Especially if you have a one-page application, a business website, or a web app with only a handful of components. The good news is you can always refactor a small project to start using Redux later.
Is React query better than Redux? ›
A major advantage of React Query is that it is far simpler to write than React Redux. In React Redux, an operation to optimistically update a field requires three actions (request, success, and failure), three reducers (request, success, and failure), one middleware, and a selector to access the data.
Is Redux really necessary? ›Yet, you don't always need Redux to manage the state of your application. Applications that consist of mostly simple UI changes most often don't require a complicated pattern like Redux. Sometimes, old-fashioned state sharing between different components works as well and improves the maintainability of your code.
What are 3 main concepts of Redux? ›- Single source of truth The global state of your application is stored in an object tree within a single store. ...
- State is read-only The only way to change the state is to emit an action, an object describing what happened. ...
- Changes are made with pure functions
But in some apps, Redux is just plain overkill where Context API is more suited. And in some cases, you don't need either, using local state is perfectly fine. Examples of using Context API in smaller applications would be to update the selected language or colour theme.
Why we use Redux instead of localStorage? ›Redux and localStorage have different use cases actually. Redux you'll use to manage your application state across multiple components. Local Storage you'll use to persist properties in the browser for later usage. The problem is that any change on your localStorage won't reflect on your application.
What is Nextjs not good for? ›Next. js is not very flexible when it comes to routing. The default approach is page-based, where you specify whether to generate those pages server-side, client-side or static. While this is good for simple applications, if you need something more complex, you'll need to write a lot more code and make use of Node.
What database should I use with Nextjs? ›Prisma is a next-generation ORM for Node. js & TypeScript. It's the easiest way to work with a database in Next. js.
Can you use React and Nextjs together? ›Next. js is a widely-used framework for building React applications that offer server-side rendering, automatic code-splitting, static exporting options, and easy production builds. It also relieves a lot of the general headaches involved with creating production-ready React applications.
Does Netflix use NextJS? ›Companies like Vercel, Netflix, Hulu, Expo, etc, are using NextJS for their applications.
Is NextJS faster than React? ›The major difference between Next JS and React JS is performance. If we talk about Next. js applications, they are extremely fast because of the static destinations and server-side rendering. Of course, they are viable due to many performance enhancement features, such as Image Optimization.
Can NextJS replace backend? ›
Next. js eliminates the need for a backend framework by taking it one step further. It allows you to create React applications that are completely server-rendered. This means that the user's browser will download a complete HTML page, including all the necessary assets like JavaScript files, CSS files, and images.
What is the replacement of Redux? ›The simplest alternative to Redux is to use React's built in Contexts functionality. One of the many important pieces of functionality state management libraries provide is the ability to access content across multiple distant components.
What is the easiest database to use with NextJS? ›Prisma is the perfect companion if you need to work with a database in a Next. js app. You can decide whether to access your database with Prisma at build time ( getStaticProps ), at request time ( getServersideProps ), using API routes, or by entirely separating the backend out into a standalone server.
Is NextJS GOOD FOR REST API? ›RESTful APIs allow you to improve scalability, are cacheable and flexible. API Routes are one of the most powerful features in Next. js because they let you build backend APIs without needing to create a custom server or spin up a new project/service.
What are the cons of NextJS? ›- No ready support of dynamic routing: Unlike React, Next. js needs Node. ...
- Time-consuming process for the development of large websites: Next. js is not very fast when it comes to site building. ...
- Chance of being locked in: Entering Next.
Next. js is a flexible React framework that gives you building blocks to create fast web applications. It is often called the fullstack React framework as it makes it possible to have both frontend and backend applications on the same codebase doing so with serverless functions.
Is NextJs better than create React app? ›Should I Use Next JS or CRA? Typically if you have an application that will only be used behind a login, CRA is a good choice. However, if you have an application for which SEO is important and fast page loads are critical, then Next JS is the right solution.
Which is better Nodejs or NextJs? ›Node. js provides a very vast framework and includes many libraries to support every need a developer might come across. Next. js enhances the user experience by introducing server-side rendering with a lower threshold for developers.