Next.js

最近在写组件库,关注到了 Next.js,项目中也正在使用,现在把它整理成文档记录一下,也希望可以帮助需要的同学。

那么,什么是 Next.js ?

它是一个 React 开发框架。

通常使用 React 开发项目时,需要做配置打包、编译等等复杂繁琐的工作。Next.js 提供了一个解决方案,开发人员可以把精力放在业务上,而不必关心项目的配置。

它能解决什么问题?
  • 自动编译和打包

  • 热加载

  • 预渲染、客户端渲染、服务器渲染

  • 静态和动态路由

  • 静态资源

  • 代码拆分

它有什么特点?
  • 基于页面的路由方案(/pages)

  • 预渲染,支持在页面级的 静态生成 (SSG) 和 服务器端渲染 (SSR)

  • 自动根据页面进行代码分割

  • 内置 CSS 、 Sass 、.less 和 .styl 的支持,并支持任何 CSS-in-JS 库

  • 支持定制 Babel 和 Webpack 的配置项

  • 支持热更新

  • 利用 Serverless Functions 及 API 路由 构建 API 功能

如何创建新应用并使用呢?

创建应用
npx create-next-app nextjs-demo --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"

上面命令的主要作用是通过调用 create-next-app 工具来创建一个 Next.js 项目。通过 --example 参数指定使用 此模板 。

运行应用

首先,进行文件目录:

cd nextjs-demo

其次,启动应用:

npm run dev

这时,在浏览器打开 http://localhost:3000/ 来运行应用。

查看应用
编辑页面

首先,找到并打开 /pages/index.js 页面。

其次,修改标题,Welcome to 改成 Learn 并保存。

最后,查看页面(Welcome to 已改成 Learn)。

查看页面
路由

Next.js 没有路由配置文件,采用的是约定式路由。即 pages 文件夹下创建的文件,都会默认生成以文件名命名的路由。

例如:
pages/index.js 代表的是入口 / 路由。
pages/about/policy.js 代表的是 /about/policy 路由。
pages/about/index.js 代表的是 /about 路由。
pages/about.js 代表的是 /about 路由。

页面导航需要借助 next/link 组件。

组件 接收字符串,也可以是 URL 对象,而且它会自动格式化生成 URL 字符串。

使用方法如下:

import Link from 'next/link'
...

   About Page

...

此时如果想给路由传参数,可以使用 query string ,也可以使用 URL 对象:


   About Page
 

// 将生成 URL 字符串/about?title=hello

  here

当取参数的时候,可以使用框架提供的 withRouter 方法,参数封装在 query 对象中:

import { withRouter } from 'next/router'

const Page = withRouter(props => (
  

{props.router.query.title}

)) export default Page

如果希望浏览器地址栏不显示 query string,可以使用as属性:

{props.title}

此时,浏览器的地址栏将显示 localhost:3000/p/123

替换路由

标签添加 replace 不会产生新的路由。


   here

注意: 的默认行为会滚动到页面顶部。当有 hash 定义时(#),页面将会滚动到对应的 id 上,就像 标签一样。为了预防滚动到顶部,可以给 加 scroll={false} 属性

命令式

除了页面导航,也可以使用框架内置的 next/router 实现客户端路由切换。

import Router from 'next/router'

const handler = () =>
  Router.push({
    pathname: '/about',
    query: { name: 'Zeit' }
  })
...
Click here to read more
...

可通过 push 或 replace 进行跳转,参数是 URL 对象(与 组件的 URL 对象一样)。

支持在页面跳转之前进行拦截,只需要监听popstate

import Router from 'next/router'

Router.beforePopState(({ url, as, options }) => {
  // 只有 / 和 /other 可以正常返回
  if (as !== "/" || as !== "/other") {
    window.location.href = as
    return false
  }

  return true
});

beforePopState 中返回 false,Router 将不会执行 popstate 事件。

Router 对象的 API:

  • route 当前路由的 String 类型
  • pathname 不包含查询内容的当前路径,为 String 类型
  • query 查询内容,被解析成 Object 类型, 默认为 {}
  • asPath 展现在浏览器上的实际路径,包含查询内容,为 String 类型
  • push(url, as=url) 页面渲染第一个参数 url 的页面,浏览器栏显示的是第二个参数 url
  • replace(url, as=url) 页面渲染第一个参数 url 的页面,浏览器栏显示的是第二个参数 url
  • beforePopState(cb=function) 在路由器处理事件之前拦截

路由事件

如果业务复杂,需要监听路由,可以监听下面的事件:

  • routeChangeStart(url) 路由开始切换时触发

  • routeChangeComplete(url) 完成路由切换时触发

  • routeChangeError(err, url) 路由切换报错时触发

  • beforeHistoryChange(url) 浏览器 history 模式开始切换时触发

  • hashChangeStart(url) 开始切换 hash 值但是没有切换页面路由时触发

  • hashChangeComplete(url) 完成切换 hash 值但是没有切换页面路由时触发

如何监听和取消呢?

在路由切换时监听事件:

const handleRouteChange = url => {
  console.log('App is changing to: ', url)
}

Router.events.on('routeChangeStart', handleRouteChange)

取消监听事件:

Router.events.off('routeChangeStart', handleRouteChange)

路由取消事件:

Router.events.on('routeChangeError', (err, url) => {
  if (err.cancelled) {
    console.log(`Route to ${url} was cancelled!`)
  }
})
代码分割
import cowsay from 'cowsay-browser'

...
  {cowsay.say({ text: 'hi there!' })}
...

页面只会加载通过 import 导入的和用到的代码。即:不会加载不需要的代码。

如想实现组件懒加载,可以通过框架提供的 next/dynamic 工具函数。

支持 SSR

import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(import('../components/hello'))

...
  

HOME PAGE is here!

...

不支持 SSR

import dynamic from 'next/dynamic'

const DynamicComponentWithNoSSR = dynamic(import('../components/hello3'), {
  ssr: false
})

...
  

HOME PAGE is here!

...

同时加载多个模块

import dynamic from 'next/dynamic'

const Hello = dynamic({
  modules: () => {
    const components = {
      Hello1: import('../components/hello1'),
      Hello2: import('../components/hello2')
    }

    return components
  },
  render: (props, { Hello1, Hello2 }) =>
    

{props.title}

}) export default () =>
CSS

支持嵌入样式

Hello world

scoped!

内嵌样式

hello world

使用 CSS / Sass / Less / Stylus 样式文件

需要配置默认文件 next.config.js

静态资源

静态资源默认是在 public 文件夹下,代码可直接引用。

Vercel Logo

也可以将静态资源放在 static 文件夹下,代码引用时可通过 /static/ 来引入相关的静态资源。

my image

注意:不要自定义静态文件夹的名字,只能叫 static ,因为只有这个名字
Next.js 才会把它当作静态资源。

生成
import Head from 'next/head'

...
My page title

Hello world!

...

注意:只有后面的 head 会最终执行。

预加载页面

Next.js 的预加载功能只预加载 JS 代码。当页面渲染时需要等待数据请求。

添加 prefetch 属性

import Link from 'next/link'

...
  
...

命令式

import React from 'react'
import { withRouter } from 'next/router'

class MyLink extends React.Component {
  componentDidMount() {
    const { router } = this.props
    // 预加载页面
    router.prefetch('/dynamic')
  }

  render() {
    const { router } = this.props
    return (
       
    )
  }
}

export default withRouter(MyLink)
总结

Next.js 是一个很好用的开发框架,用最少的配置就可以正常开发,降低了开发人员业务外的繁琐工作,因其内置的特性,使得开发人员可以快速开发。

你可能感兴趣的:(Next.js)