Next.js + Redux Integration

Thomas Charlesworth
Frontend Weekly
Published in
3 min readNov 20, 2017

--

Writing a SPA (Single page app) is something I’ve been interested in for a long time. I’ve spent the last year learning and developing apps on React, however, there was always one thing I overlooked and never properly took into account. That’s SEO.

Next.js provides that server side rendering factor we need for great SEO that we just can’t get compared to client side rendering that popular boiler plates such as create-react-app+RR4 are based on.

This tutorial isn’t going to teach you how to implement SEO capabilities nor will it teach you redux, but will give you an idea on how to setup a Next.js application alongside Redux to get your SSR react app started.

Getting Started:

    $ npm install -g create-next-app
$ create-next-app ssrapp
$ cd ssrapp
$ npm install --save redux react-redux
$ npm run dev

Once those are done, head over to localhost:3000 on your browser and you should see this:

create-next-app boilerplate

Open up the project in your editor such as Visual Studio Code.

Let’s clean up index.js to this:

export default () => (    <div>        <div>            <h1>Home Page</h1>        </div>        <style jsx>{`        `}</style>    </div>)

Let’s make a second page called about.js. Do this in the pages folder “./pages/about.js”

export default () => (    <div>        <div>            <h1>About Page</h1>        </div>        <style jsx>{`        `}</style>    </div>)

You can check out these new pages @ localhost:3000 and localhost:3000/about

With Next.js, routing is done automatically when you place files in the pages folder. You can do dynamic routing such as localhost:3000/users/:id, however, this requires that you install a routing library. I can recommend “next-routes” to you as it is quite easy to setup.

The next thing we’re going to do is create a wrapper for every page. This wrapper will allow us to wrap every page with a Provider for our redux store and also allow us to import stuff once that will affect every page. Its basically a template where every page can extend.

Next we’ll create our template. Go ahead and create a page.js file in your components folder “./components/page.js”

import React from 'react';const page = (Page) => {    return(        class PageWrapper extends React.Component{            render(){                return(                    <Page />                )            }        }    )}export default page;

Now we’ll need to edit index.js and about.js pages.

Here we imported the page wrapper and exported our index page into the page wrapper.

import Page from '../components/page';const page = () => (    <div>        <div>            <h1>Home Page</h1>        </div>        <style jsx>{`        `}</style>    </div>)export default Page(page);

Do the exact same for “./pages/about.js”

Let’s go ahead and get redux implemented now. Since page.js is the wrapper for all our pages, we can go ahead and import our store here and wrap our page in a provider.

import React from 'react';import { Provider } from 'react-redux';import store from '../store/store';const page = (Page) => {    return (        class PageWrapper extends React.Component {            render() {                return (                    <Provider store={store}>                        <Page />                    </Provider>                )            }        }    )}export default page;

Finally, let’s connect all pages. Follow this format for both index.js and about.js — In summary, import connect from ‘react-redux’, then connect your ‘page’ const and then use the Page wrapper to wrap the export. In order of things happening, it goes:

Provider -> connect() -> page

Don’t make the mistake of doing connect(state=>state)(Page(page)). This would go in order of this which is WRONG:

connect() -> Provider -> page

import { connect } from 'react-redux';import Page from '../components/page';const page = (props) => {    console.log(props)
return(
<div> <div> <h1>Home Page</h1> </div> <style jsx>{` `}</style> </div>
)
}export default Page(connect(state=>state)(page));
Le final product @ localhost:3000

Fin.

--

--