1 CSS / Sass / Less / Stylus files
具体用法见下链接
2 静态文件服务(如图像)
在根目录下新建文件夹叫static。代码可以通过/static/来引入相关的静态资源
[cc lang=”js”]export default () => [/cc]
head 组件
[cc lang=”js”]import Head from ‘next/head’
export default () => (
Hello world!
)[/cc]
只有第二个[cc lang=”html”][/cc]才被渲染。
注意:在卸载组件时,的内容将被清除。请确保每个页面都在其定义了所需要的内容,而不是假设其他页面已经加过了
获取数据以及组件生命周期
页面初始 数据
当页面渲染时加载数据,我们使用了一个异步方法getInitialProps 返回json 对象,绑定到函数或类的静态方法,这样props 就能获得这个对象。
注意: 1. 初始页面加载 getInitialProps 是在服务端运行的,不要把 getInitialProps 用到 类库带到 客户端, 具体方法见 https://www.michnal.com/?p=794
2. 当用户 在客户端 通过 Link 或routing APIs 导航 才在客户端执行
3. getInitialProps 不能用在 子组件, 要用pages 里面根组件
getInitialProps入参对象的属性如下:
pathname – URL 的 path 部分
query – URL 的 query 部分,并被解析成对象
asPath – 显示在浏览器中的实际路径(包含查询部分),为String类型
req – HTTP 请求对象 (只有服务器端有)
res – HTTP 返回对象 (只有服务器端有)
jsonPageRes – 获取数据响应对象 (只有客户端有)
err – 渲染过程中的任何错误
路由
客户端路由行为与浏览器很相似:
1.组件获取
2.如果组件定义了getInitialProps,数据获取了。如果有错误情况将会渲染 _error.js。
3. 1和2都完成了,pushState执行,新组件被渲染。
Link
[cc lang=”js”]
const as = {
pathname: ‘/about/next’,
hash: ‘title-1’
}
// 可以加as 属性 表示浏览器显示 url , href 表示page 路径下js 文件
here
to read more
[/cc]
注意:可以使用<Link prefetch>使链接和预加载在后台同时进行,来达到页面的最佳性能。
[cc lang=”js”]
import Router, { withRouter } from ‘next/router’
const handleClick = () => Router.push(href, as)
export default withRouter(({ router: { query } }) => (
About {query.name}
{query.name === ‘zeit’ ? (
Go to home page
) : (
)}
))[/cc]
路由命令式导航
Dynamic Routing
consider the following page pages/post/[pid].js:
[cc lang=”js”]
//pages/post/[pid].js:
import { useRouter } from ‘next/router’
const Post = () => {
const router = useRouter()
const { pid } = router.query
return
Post: {pid}
}
export default Post
///post/abc?foo=bar will have the query object: { foo: ‘bar’, pid: ‘abc’ }.
[/cc]
Any route like /post/1, /post/abc, etc will be matched by pages/post/[pid].js.
拦截器 popstate
你可能想监听popstate,在路由跳转前做一些动作。 比如,你可以操作 request 或强制 SSR 刷新
[cc lang=”js”]
import Router from ‘next/router’
Router.beforePopState(({ url, as, options }) => {
// I only want to allow these two routes!
if (as !== “/” || as !== “/other”) {
// Have SSR render bad routes as a 404.
window.location.href = as
return false
}
return true // 返回 false,Router将不会执行popstate事件
});[/cc]
以上Router对象的 API 如下:
route – 当前路由的String类型
pathname – 不包含查询内容的当前路径,为String类型
query – 查询内容,被解析成Object类型. 默认为{}
asPath – 展现在浏览器上的实际路径,包含查询内容,为String类型
push(url, as=url) – 页面渲染第一个参数 url 的页面,浏览器栏显示的是第二个参数 url
replace(url, as=url) – performs a replaceState call with the given url
beforePopState(cb=function) – 在路由器处理事件之前拦截.
push 和 replace 函数的第二个参数as,是为了装饰 URL 作用。如果你在服务器端设置了自定义路由将会起作用。
路由事件
routeChangeStart(url) – 路由开始切换时触发
routeChangeComplete(url) – 完成路由切换时触发
routeChangeError(err, url) – 路由切换报错时触发
beforeHistoryChange(url) – 浏览器 history 模式开始切换时触发
hashChangeStart(url) – 开始切换 hash 值但是没有切换页面路由时触发
hashChangeComplete(url) – 完成切换 hash 值但是没有切换页面路由时触发
这里的url是指显示在浏览器中的 url。如果你用了Router.push(url, as)(或类似的方法),那浏览器中的 url 将会显示 as 的值。
[cc lang=”js”]const handleRouteChange = url => {
console.log(‘App is changing to: ‘, url)
}
Router.events.on(‘routeChangeStart’, handleRouteChange)
Router.events.off(‘routeChangeStart’, handleRouteChange) //off事件去取消监听
//如果路由加载被取消(比如快速连续双击链接)
Router.events.on(‘routeChangeError’, (err, url) => {
if (err.cancelled) {
console.log(`Route to ${url} was cancelled!`)
}
})
[/cc]
浅层路由
浅层路由允许你改变 URL 但是不执行getInitialProps生命周期。你可以加载相同页面的 URL,得到更新后的路由属性pathname和query,并不失去 state 状态。
注意: 浅层路由只作用于相同 URL 的参数改变,
[cc lang=”js”]// Current URL is “/”
const href = ‘/?counter=10’
const as = href
Router.push(href, as, { shallow: true })
//在组件里查看this.props.router.query你将会看到更新的 URL。
[/cc]
你可以在componentdidupdate钩子函数中监听 URL 的变化。
[cc lang=”js”]componentDidUpdate(prevProps) {
const { pathname, query } = this.props.router
// verify props have changed to avoid an infinite loop
if (query.id !== prevProps.router.query.id) {
// fetch data based on the new query
}
}[/cc]
命令式 prefetch 的支持
[cc lang=”js”]componentDidMount() {
const { router } = this.props
router.prefetch(‘/dynamic’)
}[/cc]
自定义服务端路由
禁止文件路由
默认情况,Next将会把/pages下的所有文件匹配路由(如/pages/some-file.js 渲染为 site.com/some-file)
[cc lang=”js”]
// next.config.js
module.exports = {
useFileSystemPublicRoutes: false
}
// 注意useFileSystemPublicRoutes只禁止服务端的文件路由;但是客户端的还是禁止不了。
//可以通过 配置客户端路由不能跳转文件路由
import Router from ‘next/router’
Router.beforePopState(({ url, as, options }) => {
// I only want to allow these two routes! zhi
if (as !== ‘/’ || as !== ‘/other’) {
// Have SSR render bad routes as a 404.
window.location.href = as
return false
}
return true
})
[/cc]
动态前缀
有时你需要设置动态前缀,可以在请求时设置assetPrefix改变前缀
动态导入
你可以动态导入 JavaScript 模块(如 React 组件)。
动态导入相当于把代码分成各个块管理。Next.js 服务端动态导入功能,你可以做很多炫酷事情。
[cc lang=”js”]
//基础支持
import dynamic from ‘next/dynamic’
const DynamicComponent = dynamic(import(‘../components/hello’))
export default () =>
HOME PAGE is here!
[/cc]
自定义<App>
在page 页面组件的基础上增加一些内容, 比如 页面布局, 使用componentDidCatch自定义处理错误 和 注入额外的数据
[cc lang=”js”]
import App, {Container} from ‘next/app’
import React from ‘react’
export default class MyApp extends App {
static async getInitialProps ({ Component, router, ctx }) {
let pageProps = {}
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx)
}
return {pageProps}
}
render () {
const {Component, pageProps} = this.props
return
}
}[/cc]
自定义<Document>
Next.js会自动定义文档标记,比如,你从来不需要添加,
[cc lang=”js”]// _document is only rendered on the server side and not on the client side
// Event handlers like onClick can’t be added to this file
// ./pages/_document.js
import Document, { Head, Main, NextScript } from ‘next/document’
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { …initialProps }
}
render() {
return (
)
}
}[/cc]
注意:外的 React 组件将不会渲染到浏览器中,所以那添加应用逻辑代码。如果你页面需要公共组件(菜单或工具栏),可以参照上面说的App组件代替。
自定义错误处理
404和500错误客户端和服务端都会通过error.js组件处理。如果你想改写它,则新建_error.js在文件夹中:
[cc lang=”js”]import React from ‘react’
export default class Error extends React.Component {
static getInitialProps({ res, err }) {
const statusCode = res ? res.statusCode : err ? err.statusCode : null;
return { statusCode }
}
render() {
return (
{this.props.statusCode
? `An error ${this.props.statusCode} occurred on server`
: ‘An error occurred on client’}
)
}
}[/cc]
渲染内置错误页面
如果你想渲染内置错误页面,你可以使用next/error:
自定义配置
如果你想自定义 Next.js 的高级配置,可以在根目录下新建next.config.js文件(与pages/ 和 package.json一起)
注意:next.config.js是一个 Node.js 模块,不是一个 JSON 文件,可以用于 Next 启动服务已经构建阶段,但是不作用于浏览器端。
1.设置自定义构建目录
2. 禁止 etag 生成 //你可以禁止 etag 生成根据你的缓存策略。如果没有配置,Next 将会生成 etags 到每个页面中。
3.配置 onDemandEntries //Next 暴露一些选项来给你控制服务器部署以及缓存页面:
4. 配置构建 ID
Next.js 使用构建时生成的常量来标识你的应用服务是哪个版本。在每台服务器上运行构建命令时,可能会导致多服务器部署出现问题。为了保持同一个构建 ID,可以配置generateBuildId函数:
自定义 webpack 配置
Next.js 支持 IE11 和所有的现代浏览器使用了@babel/preset-env。为了支持 IE11,Next.js 需要全局添加Promise的 polyfill。
[cc lang=”js”]module.exports = {
webpack: function (cfg) {
const originalEntry = cfg.entry
cfg.entry = async () => {
const entries = await originalEntry()
if (
entries[‘main.js’] &&
!entries[‘main.js’].includes(‘./client/polyfills.js’)
) {
entries[‘main.js’].unshift(‘./client/polyfills.js’)
}
return entries
}
return cfg
}
}[/cc]
多 zone 合并 项目
一个 zone 时一个单独的 Next.js 应用。如果你有很多 zone,你可以合并成一个应用。
例如,你如下有两个 zone:
https://docs.my-app.com 服务于路由 /docs/**
https://ui.my-app.com 服务于所有页面
有多 zone 应用技术支持,你可以将几个应用合并到一个,而且可以自定义 URL 路径,使你能同时单独开发各个应用。
AMP Support