Next JS React Redux - Project setup


Posted 2 months ago by Ryan Dhungel

Category: Next JS SSR Redux JavaScript React

Viewed 194 times

Estimated read time: 6 minutes

Course of the day!

Laravel with React JS - Build Twitter Like Real Time Web App

Laravel with React JS - Build Twitter Like Real Time Web App

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);