Next.js v4.1.4 文档中文翻译【转载】

-- 获取的响应数据对象Fetch (只存在于客户端)
-err- 渲染时发生错误抛出的错误对象
译者注:
基于在服务器端和客户端的不同表现,例如req的存在与否,可以通过此来区分服务器端和客户端 。
路由
可以通过组件来实现客户端在两个路由间的切换功能,例如下面两个页面:
// pages/index.jsimport Link from 'next/link'export default () =>

Click{' '} here {' '} to read more

// pages/about.jsexport default () => Welcome to About!

注意:可以使用来让页面在后台同时获取和预加载,以获得最佳的页面加载性能
客户端路由行为与浏览器完全相同:
获取组件如果组件定义了,那么进行数据的获取,如果抛出异常,则将渲染.js在步骤1和步骤2完成后,开始执行,接着新组件将会被渲染
每一个顶层组件都会接收到一个url属性,其包括了以下API:
push以及的第二个参数as提供了额外的配置项,当你在服务器上配置了自定义路由的话,那么此参数就会发挥作用 。
译者注1:
上面那句话的意思是,as可以根据服务器端路由的配置作出相应的 路由改变,例如,在服务器端,你自定义规定当获取/a的path请求的时候,返回一个位于/b目录下的页面,则为了配合服务器端的这种指定,你可以这么定义组件:a 。
这种做法有一个好处,那就是尽管你将/a请求指定到了/b页面,但是因为as的值为/a,所以编译后的DOM元素显示的链接的href值为/a,但是当真正点击链接时,响应的真正页面还是/b
译者注2:
组件主要用于路由跳转功能,其可以接收一个必须的子元素(DOM标签或者纯文字等)
1. 如果添加的子元素是DOM元素,则Link会为此子元素赋予路由跳转功能;
2. 如果添加的元素是纯文字,则默认转化为a标签,包裹在此文字外部(即作为文字的父元素),如果当前组件有jsx属性的scope CSS,这个a标签是不会受此scope CSS影响的,也就是说,不会加上以jsx开头的类名 。
需要注意的是,直接添加纯文字作为子元素的做法如今已经不被赞成了() 。
URL 对象
组件可以接收一个URL对象,此URL对象将会被自动格式化为URL字符串 。
// pages/index.jsimport Link from 'next/link'export default () =>
Click{' '} here {' '} to read more

上述代码中组件的将会根据href属性的对象值生成一个/about?name=Zeit的URL字符串,你也可以在此URL对象中使用任何已经在Node.js URL中定义好了的属性来配置路由 。
替换 ()而非追加(push)路由url
组件默认将新的URL追加 (push)到路由栈中,但你可以使用属性来避免此追加动作(直接替换掉当前路由) 。
// pages/index.jsimport Link from 'next/link'export default () =>
Click{' '} here {' '} to read more

让组件支持事件
anythat. In case you don’tantag, it will only addand won’t pass .
标签支持所有支持事件的组件(即只要某组件或者元素标签支持事件,则就能够为其提供跳转路由的功能) 。如果你没有给标签添加一个标签的子元素的话,那么它只会执行给定的事件,而不是执行跳转路由的动作 。
// pages/index.jsimport Link from 'next/link'export default () =>Click{' '} "/static/image.png" />
将的href暴露给其子元素(child)
如果的子元素是一个标签并且没有指定href属性的话,那么我们会自动指定此属性(与的herf相同)以避免重复工作,然而有时候,你可能想要通过一个被包裹在某个容器(例如组件)内的标签来实现跳转功能,但是Link并不认为那是一个超链接,因此,就不会把它的href属性传递给子元素,为了避免此问题,你应该给Link附加一个属性,强制让Link将其href属性传递给它的子元素 。
import Link from 'next/link'import Unexpected_A from 'third-library'export default ({ href, name }) => {name}
命令式路由
你可以使用next/来实现客户端侧的页面切换
import Router from 'next/router'export default () =>Click () => Router.push('/about')}>here to read more
上述代码中的对象拥有以下API:
push以及的第二个参数as提供了额外的配置项,当你在服务器上配置了自定义路由的话,那么此参数就会发挥作用 。
为了使用编程的方式而不是触发导航和组件获取的方式来切换路由,可以在组件内部使用props.url.push和props.url.
译者注:
除非特殊需要,否则在组件内部不赞成()使用props.url.push和props.url.,而是建议使用next/的相关API 。
URL 对象
命令式路由 (next/)所接收的URL对象与的URL对象很类似,你可以使用相同的方式来push和路由URL
import Router from 'next/router'const handler = () => Router.push({ pathname: '/about', query: { name: 'Zeit' } }) export default () =>Click here to read more
命令式路由 (next/)的URL对象的属性及其参数的使用方法和组件的完全一样 。
路由事件
你还可以监听到与相关的一些事件 。
以下是你所能够监听的事件:
the URL shown in the . If you .push(url, as)(or ), then the valuebeas.
上面API中的url参数指的是浏览器地址栏显示的链接地址,如果你使用.push(url, as)(或者类似的方法)来改变路由,则此值就将是as的值
下面是一段如何正确地监听路由事件的示例代码:
Router.onRouteChangeStart = url => {console.log('App is changing to: ', url)}
如果你不想继续监听此事件了,那么你也可以很轻松地卸载掉此监听事件,就像下面这样:
Router.onRouteChangeStart = null
如果某个路由加载被取消掉了(例如连续快速地单击两个链接),将会被执行 。此方法的第一个参数err对象中将包括一个值为true的属性 。
Router.onRouteChangeError = (err, url) => {if (err.cancelled) {console.log(`Route to ${url} was cancelled!`)}}
如果你在一次项目新部署的过程中改变了路由,那么我们就无法在客户端对应用进行导航,必须要进行一次完整的导航动作(译者注:意思是无法像正常那样通过PWA的方式进行导航),我们已经自动帮你做了这些事 。
不过,你也可以通过Route.事件对此进行自定义操作,就像下面这样:
Router.onAppUpdated = nextUrl => {// persist the local statelocation.href = http://www.kingceram.com/post/nextUrl}
译者注:
一般情况下,上述路由事件的发生顺序如下:
1.
2.
3.
浅层路由
浅层路由( )允许你在不触发的情况下改变路由(URL),你可以通过要加载页面的url来获取更新后的和query,这样就不会丢失路由状态(state)了 。
你可以通过调用.push或.,并给它们加上: true的配置参数来实现此功能,下面是一个使用示例:
// Current URL is "/"const href = http://www.kingceram.com/post/'/?counter=10'const as = hrefRouter.push(href, as, { shallow: true })
现在,URL已经被更新到了/?=10,你可以在组件内部通过this.props.url来获取此URL
你可以在Props钩子函数中获取到URL的变化,就像下面这样:
componentWillReceiveProps(nextProps) {const { pathname, query } = nextProps.url// fetch data based on the new query}
注意:
浅层路由只会在某些页面上起作用,例如,我们可以假定存在另外一个名为about的页面,然后执行下面这行代码:
Router.push('/about?counter=10', '/about?counter=10', { shallow: true })
因为这是一个新的页面(/about?=10),所以即使我们已经声明了只执行浅层路由,但当前页面仍然会被卸载掉(),然后加载这个新的页面并调用方法
使用高阶函数 HOC
Next.js v4.1.4 文档中文翻译【转载】

文章插图
如果你想在应用的任何组件都能获取到对象,那么你可以使用高阶函数,下面是一个使用此高阶函数的示例:
import { withRouter } from 'next/router'const ActiveLink = ({ children, router, href }) => { const style = { marginRight: 10, color: router.pathname === href? 'red' : 'black' } const handleClick = (e) => { e.preventDefault() router.push(href) } return ({children}) } export default withRouter(ActiveLink)
上述代码中的对象拥有和next/相同的API 。
预获取页面Pages
(下面就是一个小例子)
Next.js自带允许你预获取()页面的API
因为Next.js在服务器端渲染页面,所以应用的所有将来可能发生交互的相关链接路径可以在瞬间完成交互,事实上Next.js可以通过预下载功能来达到一个绝佳的加载性能 。[更多详细可见](Read more.)
由于Next.js只会预加载JS代码,所以在页面加载的时候,你可以还需要花点时间来等待数据的获取 。
通过组件
你可以为任何一个组件添加属性,Next.js将会在后台预加载这些页面 。
import Link from 'next/link'// example header componentexport default () =>
通过命令的方式
大部分预获取功能都需要通过组件来指定链接地址,但是我们还暴露了一个命令式的API以方便更加复杂的场景:
import Router from 'next/router'export default ({ url }) =>() => setTimeout(() => url.pushTo('/dynamic'), 100)}> A route transition will happen after 100ms {// but we can prefetch it! Router.prefetch('/dynamic')}

自定义服务器和路由
一般来说,你可以使用next start命令启动next服务,但是,你也完全可以使用编程()的方式,例如路由匹配等,来定制化路由 。
下面就是一个将/a匹配到./page/b,以及将/b匹配到./page/a的例子:
// This file doesn't not go through babel or webpack transformation.// Make sure the syntax and sources this file requires are compatible with the current node version you are running// See https://github.com/zeit/next.js/issues/1245 for discussions on Universal Webpack or universal Babelconst { createServer } = require('http') const { parse } = require('url') const next = require('next') const dev = process.env.NODE_ENV !== 'production' const app = next({ dev }) const handle = app.getRequestHandler() app.prepare().then(() => { createServer((req, res) => { // Be sure to pass `true` as the second argument to `url.parse`. // This tells it to parse the query portion of the URL. const parsedUrl = parse(req.url, true) const { pathname, query } = parsedUrl if (pathname === '/a') { app.render(req, res, '/b', query) } else if (pathname === '/b') { app.render(req, res, '/a', query) } else { handle(req, res, parsedUrl) } }).listen(3000, err => { if (err) throw err console.log('> Ready on http://localhost:3000') }) })
next API如下所示:
-next(path: , opts: )-path是Next应用当前的路由位置
-next(opts: )
上述API中的opt对象存在如下属性:
-dev(bool) 是否使用开发模式(dev)来启动Next.js- 默认为false
-dir() 当前Next应用的路由位置 - 默认为'.'
-quiet(bool) 隐藏包括服务器端消息在内的错误消息 - 默认为false
-conf() 和next..js中的对象是同一个 - 默认为{}
然后,将你(在.json中配置)的start命令()改写成= node .js 。
异步导入
Next.js支持 TC39的规范,所以你可以动态导入()模块(例如React ) 。
你可以将动态导入理解为一种将代码分割为更易管理和理解的方式 。
由于Next.js支持服务器端渲染侧(SSR)的动态导入,所以你可以用它来做一些炫酷的东西 。
1. 基本用法(同样支持SSR)
import dynamic from 'next/dynamic'const DynamicComponent = dynamic(import('../components/hello')) export default () => HOME PAGE is here!

2. 自定义 加载组件
import dynamic from 'next/dynamic'const DynamicComponentWithCustomLoading = dynamic(import('../components/hello2'), { loading: () => ...
} ) export default () => HOME PAGE is here!

3. 禁止SSR
import dynamic from 'next/dynamic'const DynamicComponentWithNoSSR = dynamic(import('../components/hello3'), { ssr: false }) export default () => HOME PAGE is here!

4. 一次性加载多个模块
import dynamic from 'next/dynamic'const HelloBundle = dynamic({modules: props => { const components = { Hello1: import('../components/hello1'), Hello2: import('../components/hello2') } // Add remove components based on props return components }, render: (props, { Hello1, Hello2 }) =>{props.title}}) export default () =>
自定义
Next.js帮你自动跳过了在为页面添加文档标记元素的操作,例如,你从来不需要主动添加、这些文档元素 。如果你想重定义这些默认操作的话,那么你可以创建(或覆写)./page/.js文件,在此文件中,对进行扩展:
// ./pages/_document.jsimport Document, { Head, Main, NextScript } from 'next/document'import flush from 'styled-jsx/server'export default class MyDocument extends Document { static getInitialProps({ renderPage }) { const { html, head, errorHtml, chunks } = renderPage() const styles = flush() return { html, head, errorHtml, chunks, styles } } render() { return ({`body { margin: 0 } /* custom! */`} {this.props.customValue}
) } }
在以下前提下,所有的钩子函数接收到的ctx都指的是同一个对象:
注意:之外的React组件都不会被浏览器初始化,如果你想在所有的页面中使用某些组件(例如菜单栏或者工具栏),首先保证不要在其中添加有关应用逻辑的内容,然后可以看看这个例子
自定义错误处理
客户端和服务器端都会捕获并使用默认组件error.js来处理404和500错误 。如果你希望自定义错误处理,可以对其进行覆写:
import React from 'react'export default class Error extends React.Component { static getInitialProps({ res, jsonPageRes }) { const statusCode = res ? res.statusCode : jsonPageRes ? jsonPageRes.status : null return { statusCode } } render() { return ({this.props.statusCode ? `An error ${this.props.statusCode} occurred on server` : 'An error occurred on client'}
) } }

使用内置的错误页面
如果你想使用内置的错误页面,那么你可以通过next/error来实现:
import React from 'react'import Error from 'next/error'import fetch from 'isomorphic-fetch'export default class Page extends React.Component { static async getInitialProps() { const res = await fetch('https://api.github.com/repos/zeit/next.js') const statusCode = res.statusCode > 200 ? res.statusCode : false const json = await res.json() return { statusCode, stars: json.stargazers_count } } render() { if (this.props.statusCode) { return } return (
Next stars: {this.props.stars}
) } }

如果你想使用自定义的错误页面,那么你可以导入你自己的错误()页面组件而非内置的next/error
译者注:
如果你只是想覆写默认的错误页面,那么可以在/pages下新建一个名为.js的文件,Next将使用此文件来覆盖默认的错误页面
自定义配置
为了对Next.js进行更复杂的自定义操作,你可以在项目的根目录下(和pages/以及.json属于同一层级)新建一个nexr..js文件
注意:next..js是一个标准的Node.js模块,而不是一个JSON文件,此文件在Next项目的服务端以及build阶段会被调用,但是在浏览器端构建时是不会起作用的 。
// next.config.jsmodule.exports = {/* config options here */}
设置一个自定义的构建(build)目录
你可以自行指定构建打包的输出目录,例如,下面的配置将会创建一个build目录而不是.next作为构建打包的输出目录,如果没有特别指定的话,那么默认就是.next
// next.config.jsmodule.exports = {distDir: 'build'}
the
Next暴露了一些能够让你自己控制如何部署服务或者缓存页面的配置:
module.exports = {onDemandEntries: {// 控制页面在内存`buffer`中缓存的时间,单位是 msmaxInactiveAge: 25 * 1000,// number of pages that should be kept simultaneously without being disposedpagesBufferLength: 2, } }
自定义配置
你可以通过next..js中的函数来扩展的配置
// This file is not going through babel transformation.// So, we write it in vanilla JS// (But you could use ES2015 features supported by your Node.js version)module.exports = {webpack: (config, { buildId, dev }) => {// Perform customizations to webpack config// Important: return the modified config return config }, webpackDevMiddleware: config => { // Perform customizations to webpack dev middleware config // Important: return the modified config return config } }
警告:不推荐在的配置中添加一个支持新文件类型(css less svg等)的,因为只会打包客户端代码,所以()不会在服务器端的初始化渲染中起作用 。Babel是一个很好的替代品,因为其给服务器端和客户端提供一致的功能效果(例如,babel---react-svg) 。
自定义 Babel 配置
为了扩展对Babel的使用,你可以在应用的根目录下新建.文件,此文件是非必须的 。
如果此文件存在,那么我们就认为这个才是真正的Babel配置文件,因此也就需要为其定义一些next项目需要的东西,并将之当做是next/babel的预设配置()
这种设计是为了避免你有可能对我们能够定制babel配置而感到诧异 。
下面是一个.文件的示例:
{"presets": ["next/babel", "stage-0"]}
CDN 支持
你可以设定项来配置CDN源,以便能够与Next.js项目的host保持对应 。
const isProd = process.env.NODE_ENV === 'production'module.exports = {// You may only need to add assetPrefix in the production.assetPrefix: isProd ? 'https://cdn.mydomain.com' : '' }
注意:Next.js将会自动使用所加载脚本的CDN域(作为项目的CDN域),但是对/目录下的静态文件就无能为力了 。如果你想让那些静态文件也能用上CDN,那你就不得不要自己指定CDN域,有种方法也可以让你的项目自动根据运行环境来确定CDN域,可以看看这个例子
项目部署
构建打包和启动项目被分成了以下两条命令:
next buildnext start
例如,你可以像下面这样为now项目配置.json文件:
{"name": "my-app","dependencies": { "next": "latest" }, "scripts": { "dev": "next", "build": "next build", "start": "next start" } }
然后就可以直接启动now项目了!
Next.js也可以使用其他的托管方案,更多详细可以看一下这部分内容‘’
注意:我们推荐你推送.next,或者你自定义的打包输出目录(到托管方案上)( have a look at‘ ’,你还可以自定义一个专门用于放置配置文件(例如.或.)的文件夹 。否则的话,使用files或者now.files来选择要部署的白名单(很明显要排除掉.next或你自定义的打包输出目录)
导出静态 HTML 页面
你可以将你的Next.js应用当成一个不依赖于Node.js服务的静态应用 。此静态应用支持几乎所有的Next.js特性,包括 异步导航、预获取、预加载和异步导入等 。
使用
首先,Next.js的开发工作没什么变化,然后创建一个Next.js的配置文件,就像下面这样:
// next.config.jsmodule.exports = {exportPathMap: function() {return { '/': { page: '/' }, '/about': { page: '/about' }, '/readme.md': { page: '/readme' }, '/p/hello-nextjs': { page: '/post', query: { title: 'hello-nextjs' } }, '/p/learn-nextjs': { page: '/post', query: { title: 'learn-nextjs' } }, '/p/deploy-nextjs': { page: '/post', query: { title: 'deploy-nextjs' } } } } }
需要注意的是,如果声明的路径表示的是一个文件夹的话,那么最终将会导出一份类似于/dir-name/index.html的文件,如果声明的路径是一个文件的话,那么最终将会以指定的文件名导出,例如上述代码中,就会导出一个.md的文件 。如果你使用了一个不是以.html结尾的文件,那么在解析此文件的时候,你需要给text/html设置一个-Type头()
通过上述的类似代码,你可以指定你想要导出的静态页面 。
接着,输入以下命令:
next buildnext export
或许,你还可以在.json文件中多添加一条命令:
{"scripts": {"build": "next build && next export" } }
现在就只需要输入这一条命令就行了:
npm run build
这样,你在out目录下就有了一个当前应用的静态网站了 。
你也可以自定义输出目录,更多帮助可以在命令行中输入next-h获取
现在,你就可以把输出目录(例如/out)部署到静态文件服务器了,需要注意的是,如果你想要部署到上的话,那么需要需要增加一个步骤
例如,只需要进入out目录,然后输入以下命令,就可以把你的应用部署到ZEIT now
now
局限性
当你输入next 命令时,我们帮你构建了应用的HTML静态版本,在此阶段,我们将会执行页面中的函数 。
所以,你只能使用对象传递给的、query和字段,而req或res则是不可用的(res和res只在服务器端可用) 。
基于此,你也无法在我们预先构建HTML文件的时候,动态的呈现HTML页面,如果你真的想要这么做(指动态构建页面)的话,请使用next start
相关技巧FAQ
可用在生产环境使用吗?
就是使用Next.js构建的 。
无论是开发者体验还是终端表现,它都超出预期,所以我们决定将它共享到社区中 。
体积有多大?
客户端包的大小根据每个应用程序的功能等不同而不尽相同 。
一个最简单的Next程序包在gzip压缩后可能只有 65kb 大小 。
它(指Next.js) 和-react-app是差不多的吗?
是也不是 。
说是,是因为二者都让你的开发变得更轻松 。
说不是,则是因为Next.js强制规定了一些目录结构,以便我们能实现更多高级的操作,例如:
- 服务器端渲染(SSR)
- 代码自动分割
此外,Next.js还内置了两个对于单页应用来说比较重要的特性:
-with lazy:(by /link)
- 修改元素的方法(通过导入next/head)
如果你想在Next.js或其他React应用中复用组件,则使用-react-app是一个很好的选择,你可以稍后将其导入以保证代码库的纯净 。
如何使用嵌入式CSS(CSS-in-JS)方案?
Next.js自带的库-jsx支持 局部()css,当然,你也可以在Next应用中添加上面所提到的任何你喜欢的代码库来使用你想要的CSS-in-JS解决方案 。
如何使用类似于 SASS / SCSS / LESS 之类的 CSS 预处理器?
Next.js自带的库-jsx支持 局部()css,当然,你也可以在Next应用中使用以下示例中的任何一种CSS预处理器方案:
Whatare ? How do Ithem?
(语法特性)我们参照V8引擎,因为V8广泛支持ES6和async以及await,所以我们也就支持这些,因为V8还不支持类装饰器(class ),所以我们也就不支持它(类装饰器)
可以看看这些以及这些
Why a new ?
Next.js isin that:
基于上述几个特点,我们能够构造出一个具有以下两个功能的简单路由:
- 每个顶级组件都会接收到一个url对象来检查url或者 修改历史记录
-组件作为类似于等标签元素的容器以便进行客户端的页面切换 。
我们已经在一些很有意思的场景下测试了路由的灵活性,更多相信可以看这里
如何自定义路由?
Next.js提供了一个,利用其我们能够让任意URL与 任何组件之间产生映射关系 。
在客户端,组件有个as属性,它能够改变获取到的URL
如何获取数据?
这由你决定,是一个 异步(async)函数(或者也可以说是一个返回的标准函数),它能够从任意位置获取数据 。
能够配合使用吗
当然,这还有个用的例子呢 。
能够配合使用Redux吗?
当然,这也有个例子 。
为什么我不能在开发服务器中访问我的静态导出路由呢?
这是一个已知的Next.js架构问题,在解决方案还没内置到框架中之前,你可以先看看这一个例子中的解决方法来集中管理你的路由 。
我可以在 Next应用中使用我喜欢的 库或工具包吗?
我们在发布第一版的时候就已经提供了很多例子,你可以看看这个目录
你们是怎么做出这个框架的?
我们力求达到的目标大部分都是从 由 Rauch给出的[设计富Web应用的 7个原则]中受到启发,PHP的易用性也是一个很棒的灵感来源,我们觉得在很多你想使用PHP来输出HTML页面的情况下,Next.js都是一个很好的替代品,不过不像PHP,我们从ES6的模块化系统中获得好处,每个文件都能很轻松地导入一个能够用于延迟求值或测试的组件或函数 。
当我们研究React的服务器端渲染时,我们并没有做出太大的改变,因为我们偶然发现了React作者 Walke写的react-page(now ) 。
【Next.js v4.1.4 文档中文翻译【转载】】 see .md