React Framework - Next.js

1 - About

Next is a React framework for server-rendered React applications.

isomorphic apps (code that runs in the browser or in node)

note from the getting started guide of Next.js

2 - Features

  • WebPack - Hot Module Replacement

3 - Steps

3.1 - Project Init

  • Create the repository

mkdir hello-next
cd hello-next

  • init - Create a new app with create-next-app (yarn under the hood) in the current directory

npm init next-app .


Pick a template » - Use arrow-keys. Return to submit.
√ Pick a template » Default starter app
Creating a new Next.js app in C:\code\hello-next.
Installing react, react-dom, and next using yarn...

The only special directory is the pages directory.

3.2 - Next Package.json Script


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

3.3 - Start Dev Server


npm run dev

3.4 - Page

Next.js is all about pages. We can create a page by exporting a React component, and putting that component inside the pages directory. Then it will have a fixed URL based on the file name.

The only special directory is the pages directory.

A page:

  • importing a custom component
  • and exporting an other React component (ie export default

import Link from 'next/link'

import Header from '../components/Header'

export default function Index() {
    return (
        <div>
            <Header />
            <p>Hello Next.js</p>
        </div>
    )
}

3.5 - Component

Use cases for shared components:

  • As common components.
  • As Layouts.

3.5.1 - Common Component

A component directory can be named anything (by convention components), the only special directory is the pages directory. You can even create the Component inside the pages directory if you need a direct URL to your component.

A React Component


import Link from 'next/link'

const linkStyle = {
  marginRight: 15
}

const Header = () => (
  <div>
    <Link href="/">
      <a style={linkStyle}>Home</a>
    </Link>
    <Link href="/about">
      <a style={linkStyle}>About</a>
    </Link>
  </div>
)

export default Header

3.5.2 - Layout

Navigation / Routing

  • client-side navigation: Link API, which is exported via next/link (handle the location.history of the browser)
  • next/link is a higher order component which only accepts the “href” and some similar props.
  • Link Works With Anything inside. Just like an anchor, a button, you can place any React components or even a div
  • The only requirement for components placed inside a Link is they should accept an onClick prop

// This is the Link API
import Link from 'next/link'

const Index = () => (
  <div>
    <Link href="/about">
      <a>About Page</a>
    </Link>
    <p>Hello Next.js</p>
  </div>
)

export default Index

3.6.2 - Route masking

  • The as prop is the URL in the browser bar (logical)
  • The href prop is the URL the app is seeing (physical)

Example:


const PostLink = props => (
  <li>
    <Link as={`/p/${props.id}`} href={`/post?title=${props.title}`}>
      <a>{props.title}</a>
    </Link>
  </li>
)

3.7 - Processing localization

3.7.1 - SSR

SSR with custom-server-and-routing

You can use any Node.js Web server with this API.

For instance, with express


const express = require('express')
const next = require('next')

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app
  .prepare()
  .then(() => {
    const server = express()

    // Custom route
    server.get('/p/:id', (req, res) => {
      const actualPage = '/post'
      const queryParams = { title: req.params.id }
      app.render(req, res, actualPage, queryParams)
    })

    server.get('*', (req, res) => {
      return handle(req, res)
    })

    server.listen(3000, err => {
      if (err) throw err
      console.log('> Ready on http://localhost:3000')
    })
  })
  .catch(ex => {
    console.error(ex.stack)
    process.exit(1)
  })

  • Install

npm install --save express
npm install --save-dev cross-env

  • Package.json

{
  "scripts": {
    "dev": "node server.js",
    "build": "next build",
    "start": "cross-env NODE_ENV=production node server.js"
  }
}

3.7.2 - SSR vs Client Side

If we can only see the message on the browser console. That's because we navigated to the post page via the client side.

When we click on a link wrapped with the Next.js <Link> component, the page transition takes place in the browser, without making a request to the server.

If you just visit a post page directly by typing the URL in the browser address (eg:- http://localhost:3000/p/975) you will see the console message printed on the server but not in the client.

3.8 - Query String

dynamic pages using query strings client side

We're injecting the router property (included the query string) into a component by calling withRouter on it


import { withRouter } from 'next/router'
import Layout from '../components/MyLayout.js'

// Query prop of router is injected into props thanks to withRouter
const Content = withRouter(props => (
    <div>
        <h1>{props.router.query.title}</h1>
        <p>This is the blog post content.</p>
    </div>
))

const Page = withRouter(props => (
    <Layout>
        <Content />
    </Layout>
))

export default Page

3.9 - Fetch data

Browser - Fetching Resources (Request/Response) in Next

Next.js comes with an async function called getInitialProps to fetch data for pages.

  • It fetch data via a remote data source and pass it as props
  • We can write our getInitialProps to work on both server and the client.

By using the getInitialProps static async function, we can fetch data and send them as props to our page.

Fetch Next Doc

Example: passing data into our Index page as the shows prop.


# a web api fetch library wrapper that works on the server and client side
npm install --save isomorphic-unfetch


import Layout from '../components/MyLayout.js'
import Link from 'next/link'
import fetch from 'isomorphic-unfetch'

const Index = (props) => (
  <Layout>
    <h1>Batman TV Shows</h1>
    <ul>
      {props.shows.map(show => (
        <li key={show.id}>
          <Link as={`/p/${show.id}`} href={`/post?id=${show.id}`}>
            <a>{show.name}</a>
          </Link>
        </li>
      ))}
    </ul>
  </Layout>
)

Index.getInitialProps = async function() {
  const res = await fetch('https://api.tvmaze.com/search/shows?q=batman')
  const data = await res.json()

  // If the message is printed on the server, it's a SSR otherwise it's a client rendering
  console.log(`Show data fetched. Count: ${data.length}`)

  return {
    // passing data into our page as the 'shows' prop.
    shows: data.map(entry => entry.show)
  }
}

export default Index

3.10 - Styling

Next has a built-in Css In Js framework called styled-jsx

Style are defined inside the <style jsx></node> element with a Js template string

Styled jsx works as a babel plugin (all necessary prefixing and CSS validation is done inside the plugin). It will parse all of the CSS and apply it in the build process. (The styles get applied without any additional runtime overhead)

It also supports having constraints inside styled-jsx. In the future, you will be able to use any dynamic variable inside styled-jsx. That is why CSS needs to go inside of a template string. ({``})

Scope of style is:

Next.js support also other solution next.js css-in-js

3.10.1 - Local


import Layout from '../components/MyLayout.js'
import Link from 'next/link'

function getPosts() {
    return [
        {id: 'hello-nextjs', title: 'Hello Next.js'},
        {id: 'learn-nextjs', title: 'Learn Next.js is awesome'},
        {id: 'deploy-nextjs', title: 'Deploy apps with ZEIT'}
    ]
}

export default function Blog() {
    return (
        <Layout>
            <h1>My Blog</h1>
            <ul>
                {getPosts().map(post => (
                    <li key={post.id}>
                        <Link as={`/p/${post.id}`} href={`/post?title=${post.title}`}>
                            <a>{post.title}</a>
                        </Link>
                    </li>
                ))}
            </ul>
            <style jsx>{`
        h1,
        a {
          font-family: 'Arial';
        }

        ul {
          padding: 0;
        }

        li {
          list-style: none;
          margin: 5px 0;
        }

        a {
          text-decoration: none;
          color: blue;
        }

        a:hover {
          opacity: 0.6;
        }
      `}</style>
        </Layout>
    )
}

3.10.2 - Global

<style jsx global></script>

Example:


npm install --save react-markdown


import Layout from '../components/MyLayout.js'
import { withRouter } from 'next/router'
import Markdown from 'react-markdown'

export default withRouter(props => (
  <Layout>
    <h1>{props.router.query.title}</h1>
    <div className="markdown">
      <Markdown
        source={`
This is our blog post.
Yes. We can have a [link](/link).
And we can have a title as well.

### This is a title

And here's the content.
     `}
      />
    </div>
    <style jsx global>{`
      .markdown {
        font-family: 'Arial';
      }

      .markdown a {
        text-decoration: none;
        color: blue;
      }

      .markdown a:hover {
        opacity: 0.6;
      }

      .markdown h3 {
        margin: 0;
        padding: 0;
        text-transform: uppercase;
      }
    `}</style>
  </Layout>
))

3.11 - HTML page generation

Next.js 3.0 comes with a feature that allows you to export an app into a set of HTML pages. See Export into a Static HTML App

3.12 - Lazy loading

3.12.1 - Code splitting

Next.js does automatic code splitting and it is based on the pages in your app. For example, if one of your modules is used at-least in half of your pages, then it moves into the main JavaScript bundle. If not, that module stays inside the page's bundle.

https://nextjs.org/learn/excel/lazy-loading-modules

3.12.2 - React Component

3.13 - Deploy

You can deploy a Next.js app to anywhere you can run Node.js.

3.13.1 - Locally

Build produce an optimized set of code for production


"scripts": {
  "build": "next build"
  "start": "next start"
  "startonlinuxport": "next start -p $PORT"
  "startonwindowsport": "next start -p %PORT%"
}


npm run build


Creating an optimized production build ...

Compiled successfully.

 ┌ /
 ├ /_app
 ├ /_document
 ├ /_error
 ├ /about
 └ /post

  • Once on the default 300 port

npm run start

  • on windows, two instances with two different ports

:: Install cross-env globally
npm install cross-env -g
:: Run on port 8000
cross-env PORT=8000 npm run startonwindowsport
:: Run on port 9000
cross-env PORT=9000 npm run startonwindowsport

3.13.2 - now

The now platform has special builder for next application called @now/next. The builder will convert the next pages into a series of individual lambdas and serves them statically. More … see Create a Next.js Application and Deploy with Now guide


module.exports = {
  target: 'serverless'
}


{
  "version": 2,
  "builds": [{ "src": "package.json", "use": "@now/next" }],
  "name": "<name-for-your-project>"
}


npm install -g now

  • run the “now” command from your terminal inside your app's root directory.

now

More Serverless Hosting - Now

4 - Support / Community

5 - App

6 - Documentation / Reference


Data Science
Data Analysis
Statistics
Data Science
Linear Algebra Mathematics
Trigonometry

Powered by ComboStrap