DEV Community

Cover image for Add Redux to a Next JS App
Nurudeen Amedu
Nurudeen Amedu

Posted on • Updated on

Add Redux to a Next JS App

In this article, I will go over how you can configure your Next JS application to use redux.

First set up your next js application

yarn create next-app next-redux
Enter fullscreen mode Exit fullscreen mode

Next we install the desired packages

yarn add redux redux-thunk next-redux-wrapper react-redux
Enter fullscreen mode Exit fullscreen mode

After that installation, create a redux folder in the root of your project, inside that folder add a types.js and store.js files, also add folders for actions and reducers.

Alt Text

In the types file, lets add a single type; for setting the name of the user

export const SET_NAME = "SET_NAME"
Enter fullscreen mode Exit fullscreen mode

In the reducers folder, add a main.js file, In this file we will create a reducer that will manage the main state of our app.

In this file we will initialize a main state with only one value for the name that defaults to guest. Then we will use a switch statement to detect the passed in action and value, the state gets updated based on the value received.

import * as t from "../types";

const main = (state = {
    name: "guest",
}, action) => {
  switch(action.type){
    case t.SET_NAME:
      return { 
        ...state,
        name: action.payload
      };
    default:
      return {...state};
    }
}

export default main;
Enter fullscreen mode Exit fullscreen mode

In the same reducers folder, we will add a rootReducer.js file, this file will combine all our reducers into one, it is most useful when you have multiple reducer files, for this article i will only be using a single reducer file, which is my main reducer.

import { combineReducers } from "redux"
import main from "./main"

const rootReducer = combineReducers({
  main: main
})

export default rootReducer;
Enter fullscreen mode Exit fullscreen mode

Next, we move to our store.js file

In this file we will create our redux store using redux and next-redux-wrapper, we will also add redux-thunk to allow us have extra functions before dispatching new values to our state.

import { createStore, applyMiddleware, compose } from "redux"
import thunk from "redux-thunk"
import { createWrapper } from "next-redux-wrapper"
import rootReducer from "./reducers/rootReducer"

const middleware = [thunk]

const makeStore = () => createStore(rootReducer, compose(applyMiddleware(...middleware)))

export const wrapper = createWrapper(makeStore)
Enter fullscreen mode Exit fullscreen mode

Now we will create our set name action, create a main.js file in the actions folder, inside it we will have a function that specifies the set name type with a new name value.

import * as t from "../types";
import axios from "axios";
import { request } from "../../util/request";

export const setInfo = (name) => dispatch => {
  dispatch({
    type: t.SET_NAME,
    payload: name
  });
}
Enter fullscreen mode Exit fullscreen mode

After you've done all of this, our directory should look like below

Alt Text

Now move to your _app.js file, it should look like;

import '../styles/globals.css'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp

Enter fullscreen mode Exit fullscreen mode

Update it to look like;

import React from "react"
import { wrapper } from "../redux/store"

const MyApp = ({ Component, pageProps}) => (
  <Component {...pageProps} />
)

export default wrapper.withRedux(MyApp);
Enter fullscreen mode Exit fullscreen mode

We've wrapped the app in the redux wrapper we created in our store file and passed props to it.
In our index.js, take out all the page content and leave an input box asking for a name.

return (
    <div className={styles.container}>
      <p>Enter a Name :</p>
      <input 
        type="text">

        </input>
        <button>
          Submit
        </button>
    </div>
  )
Enter fullscreen mode Exit fullscreen mode

Alt Text

Next we add some state management for updating and storing the value of our form using useState, we also link our index page to our redux state and finally connect the actions using mapDispatchToProps and the state using mapStateToProps, the final index.js should look like below

import { useState } from 'react'
import { connect } from "react-redux"
import { setInfo } from "../redux/actions/main"
import styles from '../styles/Home.module.css'

function Home(props) {
  const { name, setInfo } = props
  const [newName, setName] = useState("")

  return (
    <div className={styles.container}>
      <p>Enter a Name {name}:</p>
      <input 
        type="text" 
        value={newName} 
        onChange={(e) => setName(e.target.value)}>

        </input>
        <button onClick={() => setInfo(newName)}>
          Submit
        </button>
    </div>
  )
}

const mapStateToProps = state => {
 return { name: state.main.name }
}

const mapDispatchToProps = {
  setInfo
}

export default connect(mapStateToProps, mapDispatchToProps)(Home)
Enter fullscreen mode Exit fullscreen mode

To be able to debug with Redux Dev Tools, update your store.js code to;

import { createStore, applyMiddleware, compose } from "redux"
import thunk from "redux-thunk"
import { createWrapper } from "next-redux-wrapper"
import rootReducer from "./reducers/rootReducer"

const middleware = [thunk]

const composeEnhancers =
  typeof window === 'object' &&
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;

const enhancer = composeEnhancers(applyMiddleware(...middleware));

const makeStore = () => createStore(rootReducer, enhancer)

export const wrapper = createWrapper(makeStore)
Enter fullscreen mode Exit fullscreen mode

Your home page should now look like the below image, and changing the name should update the value of "guest"
Alt Text

If you find this article helpful, you can also checkout other Next JS videos on Youtube or the Full Stack Next JS Course on Udemy

Top comments (8)

Collapse
 
uwants0me_ profile image
elonplsadoptme

is there any specific reason to access redux state/store (using connect) like the way you did? why dont you use useSelector hooks from react-redux instead? and als useDispatch? is there any drawbacks using those two in nextjs?

Collapse
 
jideabdqudus profile image
jideabdqudus

Found this helpful while building my App, I;m new to Next and would like to know if there's a particular usecase for getServerSideProps and getStaticProps while building a next-redux application

Collapse
 
uwants0me_ profile image
elonplsadoptme

i can't access redux store on getServerSideProps, pls help

Collapse
 
theallegrarr profile image
Nurudeen Amedu

Can I see your repo?

Collapse
 
a_m_h_gad profile image
Jad

Great Job. Do you have a repo with this code, please

Collapse
 
theallegrarr profile image
Nurudeen Amedu
Collapse
 
a_m_h_gad profile image
Jad

thanks <3

Collapse
 
codemon profile image
Johnson awah Alfred

Awsome!! Simple