Server-Side Rendered App with Next.js, React and Redux 
Tags: javascript, react, redux, webdev
Published: 2020-01-12 17:50:31

There are many known benefits to pre-rendering your web application or rendering your web app on the server-side, some of which include better SEO, faster-load times, a better user experience for users with poor connections and many more.

This post will guide you towards getting quickly started with Next and using it to develop a React-Redux web application. 

**Note: This post is outdated and was written for Next.js versions 9.2 and lower. Please refer to [next-redux-wrapper](https://github.com/kirill-konshin/next-redux-wrapper) to see how to create an updated version Next.js-redux web app.**


Prerequisites for this post:

* Understanding of Basic React Concepts
* Understanding of Basic Redux Concepts

For the purpose of this post, after going through all the concepts, we will be creating a simple counter app with our server-side rendered app. 


###Getting Started with Next.JS <a name='nextjs-intro'></a>

Next.js is a React-Framework which makes it really easy to develop react server-side rendered apps. It also provides additional features but in this post, we will only go over rendering applications server-side with Next.js.

I highly recommend going over the [docs](https://nextjs.org/learn/basics/getting-started). This part goes over the basic principles of [next](#basic-app) and there is a lot of overlap with the documentation. I recommend going through the documentation and then proceeding to the next part of this article. Nevertheless, if the documentation are not sufficient, then you can keep reading!

If you already have Next.js installed and know the basics, you can skip to the [following](#basic-app)

To get started, we first create a project directory:

```
mkdir hello-next
```

We then initialize the project with npm:

```
cd hello-next
npm init -y
```

We then need to install `next`, `react` & `react-dom`, these are necessary dependencies for `next`:

```
npm install --save react react-dom next
```

We then need to create a 'pages' directory within our project directory. Any React files in this directory by default are mapped to the url routes based on the file-name for our server-side rendered app:

```
mkdir pages
```

A file named `index.jsx` will be mapped to the root url i.e. `localhost:3000/`.
Similarily a file named `login.jsx` will be mapped to `localhost:3000/login`
This feature is enabled by default and for our use-case, this is sufficient.

To get started with `next`, we need to edit our package.json in our project directory and replace the scripts with the following:

```
"scripts": {
  "dev": "next",
  "build": "next build",
  "start": "next start"
}
```

After doing so, everything is ready. You can now run this command in the project directory:

```
npm run dev
```

After a few seconds, the development server should be up and running and visiting `localhost:3000` will yield "404 | Page Not Found". This is because our pages directory does not have an "index.jsx" file. We can proceed to create it:

```
touch pages/index.jsx
```

We can then create a simple Hello-World index page:

```javascript
import React from 'react';

class App extends React.Component {
    render() {
        return (
            <h1> Hello World! </h1>
        );
    }
}

export default App;
```

Here we create a React Component that renders "Hello World" and visiting the root path will show the result.


Next only recognizes the default imports in the React files in the pages directory, and will only render the default Component when browsed to the URL path.

###Creating a Simple Counter App (Without Redux)<a name='basic-app'></a>

To create a simple counter app, we can do the following:

```javascript
import React from 'react';

class App extends React.Component {

    constructor(props) {
        super(props);
        
        //Initialise state
        this.state = {
            counter: 0
        };
    }

    //Updates the counter in state by +1
    incrementCounter = () => {
        this.setState(prevState => {
            this.setState({
                counter: prevState.counter + 1.
            });
        });
    };

    //Updates the counter in state by  -1
    decrementCounter = () => {
        this.setState(prevState => {
            this.setState({
                counter: prevState.counter - 1.
            });
        });
    };

    render() {
        return (
            <div>
                <button onClick={this.incrementCounter}>Increment</button>
                <button onClick={this.decrementCounter}>Decrement</button>
                <h1>{this.state.counter}</h1>
            </div>
        );
    }
}

export default App;
```

Doing so will show this result:

![Result Image](https://i.imgur.com/qpmTW5p.png)

Clicking on the appropriate buttons increment and decrements.


As you can see, `next` makes use of React and therefore working with next is simple just working with React, the only difference is that `next` automatically (Behind-the-scenes) renders the application serverside.

###Understanding Server-Side Rendering with Redux

Similar to how working with `Next` is basically just working with React. Redux web apps behave in the same way. Everything works similar to how it would work if the app was rendered on the client-side. The only challenge working with Redux is the initial Redux setup with server-side rendering and this is exactly what the following part covers. 

The official documentation, [Redux](https://redux.js.org/recipes/server-rendering/#redux-on-the-server) provides a good explanation of how server-side rendering is expected to work with Redux. The explanation states that:

>When using Redux with server rendering, we must also send the state of our app along in our response, so the client can use it as the initial state. This is important because, if we preload any data before generating the HTML, we want the client to also have access to this data. Otherwise, the markup generated on the client won't match the server markup, and the client would have to load the data again.

>To send the data down to the client, we need to:

> * create a fresh, new Redux store instance on every request;
> * optionally dispatch some actions;
> * pull the state out of store;
> * and then pass the state along to the client.

>On the client-side, a new Redux store will be created and initialized with the state provided by the server. Redux's only job on the server-side is to provide the initial state of our app. 

This might seem confusing but the important part is:

1. Initialize and create a new redux store for new user request
2. (Optional) populate the store with information, for example, you could make use of the user-cookies in the request to identify the user and populate the store with the user information.
3. Send the redux state to the client
4. The client then uses the received state to initialize the client-side redux store.

The next part will cover how we can achieve this.

###Setting-up Redux 

To get started with Redux, we will create a basic Redux app where we keep track of the counter in our state.

We need to first install redux and react-redux:

```
npm install --save redux react-redux
```

This is how our project structure will look like:

```
hello-next
	+- .next
	+- node_modules
	+- pages
	+- redux
		+- actions
		+- reducers
```

To do so we can do the following:

```
mkdir redux redux/actions redux/reducers
```

We will now create a counterReducer, which will keep track of our counter state. We can place this in the reducers folder:

```
touch redux/reducers/counterReducer.js
```

This is how the counterReducer file will look like:

```javascript
const counterReducer = (state = {value: 0}, action) => {
    return {...state};
};

export default counterReducer;
```

This will create an initial state with the counter value being set to 0

Right now our counterReducer does nothing. We can proceed to creating actions:

```
touch redux/actions/counterActions.js
```

We will just specify two actions - Increment and Decrement:

```javascript
//Action Types
export const INCREMENT_COUNTER = "INCREMENT_COUNTER";
export const DECREMENT_COUNTER = "DECREMENT_COUNTER";


//Action Creator
export const incrementCounter = () => ({
   type: INCREMENT_COUNTER
});

export const decrementCounter = () => ({
    type: DECREMENT_COUNTER
});

```

We can now modify our reducer to include these actions:

```javascript
import {DECREMENT_COUNTER, INCREMENT_COUNTER} from '../actions/counterActions';

const counterReducer = (state = {value: 0}, action) => {
    switch (action.type) {
        case INCREMENT_COUNTER:
            return {...state, value: state.value + 1};
        case DECREMENT_COUNTER:
            return {...state, value: state.value - 1};
        default:
            return {...state};
    }
};

export default counterReducer;
```

This will either increment or decrement our counter when `INCREMENT_COUNTER` or `DECREMENT_COUNTER` actions are dispatched.

We can now proceed to creating the root reducer, which will be responsible for combining all our reducers. In our case we only have 1 reducer "counterReducer", however for common practice we will proceeding to combining reducers. 

Create the rootReducer file:

```
touch redux/reducers/rootReducer.js
```

This is how our rootReducer file will look like:

```javascript
import counterReducer from './counterReducer';
import {combineReducers} from 'redux';

const rootReducer = combineReducers({
    counter: counterReducer
});

export default rootReducer;
```

This combines all our reducers into one rootReducer which we can use to initalise our redux store.

We can now proceed to creating our redux store:

```
touch redux/store.js
```


```javascript
import {createStore} from 'redux';
import rootReducer from './reducers/rootReducer';

const store = createStore(rootReducer);

export default store;
```


Now that we have our redux logic setup, we can link our application with redux, using react-redux. However to do this, we need to create a special file named "_app.jsx" located in our pages directory:

```
touch pages/_app.jsx
```

`next` uses the App component to initialize pages. We created the "_app.jsx" file to override the default App Component. To begin with, our new App Component needs to extend the default App component, so that `next` can still use it to initalise pages.

We can import the default App Component from "next/app" and create our own App component:

```javascript
import App from 'next/app';

class MyApp extends App {
    
    
}

export default MyApp;
```

However, at this moment we are doing nothing. Similar to how Redux is connected to Client-side react apps, we can connect our server-side rendered application here.

We use "Provider" provided by react-redux and connect our store:

```javascript
import App from 'next/app';
import {Provider} from 'react-redux';
import React from 'react';

class MyApp extends App {

    render() {
        return (
            <Provider store={}>

            </Provider>
        );
    }

}

export default MyApp;
```

But what do we put as the argument for store inside the Provider Component? To finish the setup we must use a static function `getInitialProps`. This function according to the `next` docs is responsible for:

>Next.js comes with [`getInitialProps`](https://nextjs.org/docs/api-reference/data-fetching/getInitialProps), which is an [`async`](https://zeit.co/blog/async-and-await) function that can be added to any page as a [`static method`](https://javascript.info/static-properties-methods).
>
>getInitialProps` allows the page to wait for data before rendering starts.` 
>
>Using `getInitialProps` will make the page opt-in to on-demand [server-side rendering](https://nextjs.org/docs/basic-features/pages#server-side-rendering).

Every page that has `getInitialProps` will be server-side rendered. If you do not include this method then the file will be rendered to static HTML at `next build` time. Including this function will allow this page to render on the server, and everything inside that function will be executed before sending the page to the client. This is helpful in cases where our page needs data that needs to be fetched. Returning anything from this function will allow that information to be sent to the client. The client can access the information returned from this function using the props of the React component.

This is also where we can choose to optionally populate our redux state before sending it to the client, adding this function to our "_app.jsx" looks like:

```javascript
import App from 'next/app';
import {Provider} from 'react-redux';
import React from 'react';
import {INCREMENT_COUNTER} from '../redux/actions/counterActions';

class MyApp extends App {

    static async getInitialProps({Component, ctx}) {
        const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {};

        //Anything returned here can be access by the client
        return {pageProps: pageProps};
    }

    render() {
        //Information that was returned  from 'getInitialProps' are stored in the props i.e. pageProps
        const {Component, pageProps} = this.props;

        return (
            <Provider store={}>
                <Component {...pageProps}/>
            </Provider>
        );
    }

}

export default MyApp;

```

ctx is a `getInitialProps` parameter referring to Context. You can read more about it [here](https://nextjs.org/docs/api-reference/data-fetching/getInitialProps#context-object)

Using `getInitialProps` in `_app.jsx` has a different interface. When using it on normal pages, `getInitialProps` only has 1 parameter `ctx`. However in our case, since we are overriding the default App Component, we have access to the  default App Component. We need to make sure if the default App component makes use of `getInitialProps`  then we need to send whatever that function returned to the client.

Moving on, to pass the store to the client, we need to wrap the original component with React-Redux's `Provider`. To make all of this work, we need to install one last library: [next-redux-wrapper](https://github.com/kirill-konshin/next-redux-wrapper)

```
npm install --save next-redux-wrapper
```

Next-redux-wrapper will enable us to create a store at every new request and it will pass it to `MyApp` (Our App Implementation) as props.

We need to make use of Next-redux-wrapper's `withRedux` wrapper and wrap our App component with it. 

> The `withRedux` function accepts `makeStore` as first argument. The `makeStore` function will receive initial state and should return a new instance of Redux `store` each time when called, no memoization needed here, it is automatically done inside the wrapper.

After connecting with next-redux-wrapper:

```javascript
import App from 'next/app';
import {Provider} from 'react-redux';
import React from 'react';
import withRedux from "next-redux-wrapper";
import store from '../redux/store';

class MyApp extends App {

    static async getInitialProps({Component, ctx}) {
        const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {};

        //Anything returned here can be accessed by the client
        return {pageProps: pageProps};
    }

    render() {
        //pageProps that were returned  from 'getInitialProps' are stored in the props i.e. pageprops
        const {Component, pageProps, store} = this.props;

        return (
            <Provider store={store}>
                <Component {...pageProps}/>
            </Provider>
        );
    }
}

//makeStore function that returns a new store for every request
const makeStore = () => store;

//withRedux wrapper that passes the store to the App Component
export default withRedux(makeStore)(MyApp);


```

After the following the changes, our app is ready! We can now use Redux as we normally would. Changing our `index.jsx` to incorporate redux.

```javascript
import React from 'react';
import {connect} from 'react-redux';
import {decrementCounter, incrementCounter} from '../redux/actions/counterActions';

class App extends React.Component {

		static getInitialProps({store}) {}

    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div>
                <button onClick={this.props.incrementCounter}>Increment</button>
                <button onClick={this.props.decrementCounter}>Decrement</button>
                <h1>{this.props.counter}</h1>
            </div>
        );
    }
}

const mapStateToProps = state => ({
    counter: state.counter.value
});

const mapDispatchToProps = {
    incrementCounter: incrementCounter,
    decrementCounter: decrementCounter,
};

export default connect(mapStateToProps, mapDispatchToProps)(App);

```

We use React-Redux's `connect` to connect the Redux state to our page, and we use `mapStateToProps` and `mapDispatchToProps` to connect our state and actionCreators to our page. 

After running the page, our React-Redux app works as expected! Clicking on the buttons Increments and/or Decrements!

Congratulations, you now know the basics of how to create a Server-side Rendered React-Redux Application using `next.js`

One thing to note is that at the moment Redux only works as a Single Page Application, what this means is that Client-side routing is the only way for the Redux store to be transferred between pages. 

This means that if the user navigates to a different URL (i.e. Server-side routing) then the server will treat it as a new client and serve an empty redux state. To learn how to persist the redux-state so that the counter values stays the same for each refresh refer to [next-redux-wrapper guide](https://github.com/kirill-konshin/next-redux-wrapper#usage-with-redux-persist). However please ensure that you update your Next.js version and the next-redux-wrapper version first and follow the updated [guide](https://github.com/kirill-konshin/next-redux-wrapper).

The code for this project can be found on [Github](https://github.com/Waqas-Abbasi/nextjs-react-redux-example)

This is the end of this post! This was my first post and I hope you enjoyed reading it! Any feedback is appreciated!

If you would like to read more yourself refer to [next-redux-wrapper repository](https://github.com/kirill-konshin/next-redux-wrapper)