Next JS React Redux - Project setup


Posted 4 months ago by Ryan Dhungel

Category: Next JS SSR Redux JavaScript React

Viewed 489 times

Estimated read time: 6 minutes

Course of the day!

Learn Laravel Building Multi User Blogging Platform with SEO

Learn Laravel Building Multi User Blogging Platform with SEO

This tutorial will show you how to build a boilerplate project using Next JS, React and Redux. The aim here is to be able to start off a Next JS project to build SSR (Server Side Rendered) React App.

 

Getting Started

 

mkdir next-app
cd next-app
touch package.json
mkdir pages
mkdir components
// package.json
{
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  }
}
npm install --save react react-dom next

 

Creating Pages

 

// pages/index.js
export default () =>Welcome to next js;

// pages/another.js
export default () =>Welcome to another page;

 

npm run dev

 

Now you can see the pages in the browser:

 

// http://localhost:3000
Welcome to next js

// http://localhost:3000/another
Welcome to another page

 

Components and props

 

// components/Hello.js
export const Hello = props =>
Hello {props.title}
;
// pages/index.js
import { Hello } from "../components/Hello";
export default () => (
 
);

Now you see Hello Ryan in http://localhost:3000/

Statefull component with scoped style

// components/Panel.js
import React, { Component } from "react";

class Panel extends Component {
    constructor() {
        super();
        this.state = { opened: false };
    }
    toggle = () => this.setState({ opened: !this.state.opened });
    render() {
        const cls = this.state.opened ? "null" : "hidden";
        return (

Title

Body
); } } export default Panel; 
// pages/index.js
import { Hello } from "../components/Hello";
import Panel from "../components/Panel";
export default () => (
 
);

Using Link

// components/NavBarNavBar.js
import Link from "next/link";

const Sep = () =>  | ;

export default () => (
);
// pages/index.js
import { Hello } from "../components/Hello";
import Panel from "../components/Panel";
import NavBar from "../components/NavBar";

export default () => (
 
);
// pages/another.js
import NavBar from "../components/NavBar";

export default () => (
Welcome to another page
);

API Request in getInitialProps()

npm install isomorphic-fetch
// pages/posts.js
import React, { Component } from "react";
import "isomorphic-fetch";
import NavBar from "../components/NavBar";

class Posts extends Component {
    static async getInitialProps() {
        const res = await fetch("http://jsonplaceholder.typicode.com/posts");
        const json = await res.json();
        return { posts: json };
    }
    render() {
        return (

Posts

{this.props.posts.map((p, i) => ({p.title}
                ))}        
       );
    }
}

export default Posts;

Instead of componentDidMount() we used getInitialProps() for SSR. Then instead of using this.state, we use this.props to loop through posts.

Bootstrap with Next JS using Next Head

// components/Navbar.js
import Link from "next/link";
import Head from "next/head";

const Sep = () =>  | ;

export default () => (
);

Styling with Bootstrap

// components/Panel.js
import React, { Component } from "react";

class Panel extends Component {
    constructor() {
        super();
        this.state = { opened: false };
    }
    toggle = () => this.setState({ opened: !this.state.opened });
    render() {
        const cls = this.state.opened ? "card-body" : "hidden";
        return (

Title

Body
); } } export default Panel; 

 

Using Redux with Next JS

 

// pages/todos.js
import NavBar from "../components/NavBar";

export default () => {
    return (
Todos

    );
};

 

npm install --save redux react-redux redux-devtools-extension redux-thunk next-redux-wrapper

 

// pages_app.js

import React from "react";
import { createStore } from "redux";
import { Provider } from "react-redux";
import App, { Container } from "next/app";
import withRedux from "next-redux-wrapper";

const reducer = (state = { foo: "" }, action) => {
  switch (action.type) {
    case "FOO":
      return { ...state, foo: action.payload };
    default:
      return state;
  }
};

const makeStore = (initialState, options) => {
  return createStore(reducer, initialState);
};

class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    // we can dispatch from here too
    ctx.store.dispatch({ type: "FOO", payload: "foo" });

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

    return { pageProps };
  }

  render() {
    const { Component, pageProps, store } = this.props;
    return (
      
        
          
        
      
    );
  }
}

export default withRedux(makeStore)(MyApp);

 

// pages.todos.js

import React, { Component } from "react";
import { connect } from "react-redux";
import NavBar from "../components/NavBar";

class Todos extends Component {
    static getInitialProps({ store, isServer, pathname, query }) {
        // dispatch page-specific actions
        store.dispatch({ type: "FOO", payload: "foo" });
        // pass custom props to page
        return { custom: "custom" };
    }
    render() {
        return (
Prop from Redux {this.props.foo}
Prop from getInitialProps {this.props.custom}

        );
    }
}
export default connect(state => ({ foo: state.foo }))(Todos);