Next.js文档地址:https://nextjs.org/
创建Next.js项目脚手架:https://github.com/zeit/create-next-app
官方Demo:https://github.com/zeit/next.js/tree/canary/examples
官方Demo已经很全了,有不懂的地方认真看下。
以下为官方文档翻译:
安装 安装next.js:1 npm install --save next react react-dom
同时添加script到package.json文件:1 2 3 4 5 6 7 { "scripts": { "dev": "next", "build": "next build", "start": "next start" } }
自动代码拆分 CSS Built-in CSS support 我们捆绑了styled-jsx以支持隔离的作用域CSS。目的是支持类似于Web Components的shadow CSS
,遗憾的是它不支持服务器渲染并且只支持JS。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 function HelloWorld() { return ( <div> Hello world <p>scoped!</p> <style jsx>{` p { color: blue; } div { background: red; } @media (max-width: 600px) { div { background: blue; } } `}</style> <style global jsx>{` body { background: black; } `}</style> </div> ); } export default HelloWorld;
有关更多示例,请参阅styled-jsx 文档。
CSS-in-JS 可以使用任何现有的CSS-in-JS解决方案。最简单的是内联样式:
1 2 3 4 5 function HiThere() { return <p style={{ color: 'red' }}>hi there</p>; } export default HiThere;
要使用更复杂的CSS-in-JS解决方案,通常必须为服务器端呈现实现样式刷新。我们通过允许您定义包装每个页面的自定义组件来实现此功能。
Importing CSS / Sass / Less / Stylus files 要支持导入.css
,.scss
,.less
或.styl
文件,您可以使用这些模块,这些模块为服务器呈现的应用程序配置合理的默认值。
@zeit/next-css @zeit/next-sass @zeit/next-less @zeit/next-stylus
Static file serving (e.g.: images) 在项目根目录中创建一个名为static的文件夹。然后,您可以从代码中使用/ static / URLs引用这些文件:
1 2 3 4 5 function MyImage() { return <img src="/static/my-image.png" alt="my image" />; } export default MyImage;
注意:不要将静态目录命名为其他任何名称。该名称是必需的,是Next.js用于提供静态资产的唯一目录。
Populating <head>
我们公开了一个内置组件,用于将元素附加到页面的<head>
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import Head from 'next/head'; function IndexPage() { return ( <div> <Head> <title>My page title</title> <meta name="viewport" content="initial-scale=1.0, width=device-width" /> </Head> <p>Hello world!</p> </div> ); } export default IndexPage;
为了避免<head>
中的重复标记,您可以使用key
属性,这将确保标记仅呈现一次:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import Head from 'next/head'; function IndexPage() { return ( <div> <Head> <title>My page title</title> <meta name="viewport" content="initial-scale=1.0, width=device-width" key="viewport" /> </Head> <Head> <meta name="viewport" content="initial-scale=1.2, width=device-width" key="viewport" /> </Head> <p>Hello world!</p> </div> ); } export default IndexPage;
Fetching data and component lifecycle 当需要状态、生命周期挂钩或初始数据填充时,可以导出React.Component
或使用无状态函数和钩子。
使用无状态函数:1 2 3 4 5 6 7 8 9 10 11 12 13 14 import React from 'react'; class HelloUA extends React.Component { static async getInitialProps({ req }) { const userAgent = req ? req.headers['user-agent'] : navigator.userAgent; return { userAgent }; } render() { return <div>Hello World {this.props.userAgent}</div>; } } export default HelloUA;
路由 Next.js不提供应用程序中所有可能的路由清单,因此当前页面不知道客户端上的任何其他页面。为了扩展性,所有后续路由都会被延迟加载。
With <Link>
可以通过一个<Link>
组件来启用路由之间的客户端转换。
对于需要硬刷新的静态页面,如使用AMP时,不需要此组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // pages/index.js import Link from 'next/link'; function Home() { return ( <> <ul> <li>Home</li> <li> <Link href="/about"> <a>About Us</a> </Link> </li> </ul> <h1>This is our homepage.</h1> </> ); } export default Home;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // pages/about.js function About() { return ( <> <ul> <li> <Link href="/"> <a>Home</a> </Link> </li> <li>About Us</li> </ul> <h1>About</h1> <p>We are a cool company.</p> </> ); } export default About;
Dynamic Routes 1 2 3 4 5 6 7 8 9 10 import { useRouter } from 'next/router'; const Post = () => { const router = useRouter(); const { postId } = router.query; return <p>My Blog Post: {postId}</p>; }; export default Post;
一个链接/post/first-post
像下面这样:
1 2 3 <Link href="/post/[postId]" as="/post/first-post"> <a>First Post</a> </Link>
With URL object 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // pages/index.js import Link from 'next/link'; function Home() { return ( <div> Click{' '} <Link href={{ pathname: '/about', query: { name: 'Zeit' } }}> <a>here</a> </Link>{' '} to read more </div> ); } export default Home;
Replace instead of push url <Link>
组件的默认行为是将一个新的urlpush
堆栈中。您可以使用replace
属性来防止添加新条目。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // pages/index.js import Link from 'next/link'; function Home() { return ( <div> Click{' '} <Link href="/about" replace> <a>here</a> </Link>{' '} to read more </div> ); } export default Home;
Using a component that supports onClick 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // pages/index.js import Link from 'next/link'; function Home() { return ( <div> Click{' '} <Link href="/about"> <img src="/static/image.png" alt="image" /> </Link> </div> ); } export default Home;
Forcing the Link to expose href to its child Disabling the scroll changes to top on page <Link>
的默认行为是滚动到页面的顶部。当定义了散列时,它将滚动到特定的id,就像普通的<a>
标记一样。为了防止滚动到top / hash scroll={false}
,可以将其添加到<Link>
。
1 2 <Link scroll={false} href="/?counter=10"><a>Disables scrolling</a></Link> <Link href="/?counter=10"><a>Changes with scrolling to top</a></Link>
Imperatively 您还可以使用next/router
1 2 3 4 5 6 7 8 9 10 11 import Router from 'next/router'; function ReadMore() { return ( <div> Click <span onClick={() => Router.push('/about')}>here</span> to read more </div> ); } export default ReadMore;
Intercepting popstate With URL object Router Events Shallow Routing useRouter Using a Higher Order Component Prefetching Pages With 1 2 3 <Link href="/about" prefetch={false}> <a>About</a> </Link>
Imperatively 大多数预取需求都由<link/>
解决,但我们也公开了一个用于高级使用的命令式API
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import { useRouter } from 'next/router'; export default function MyLink() { const router = useRouter(); return ( <> <a onClick={() => setTimeout(() => router.push('/dynamic'), 100)}> A route transition will happen after 100ms </a> {// and we can prefetch it! router.prefetch('/dynamic')} </> ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import { useRouter } from 'next/router' export default function MyLink() { const router = useRouter() useEffect(() => { router.prefetch('/dynamic') }) return ( <a onClick={() => setTimeout(() => router.push('/dynamic'), 100)}> A route transition will happen after 100ms </a> ) } export default withRouter(MyLink)
在使用React.Component
时,还可以将其添加到ComponentDidMount
生命周期方法中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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 ( <a onClick={() => setTimeout(() => router.push('/dynamic'), 100)}> A route transition will happen after 100ms </a> ); } } export default withRouter(MyLink);
API Routes AMP Support `
Enabling AMP Support 若要启用对页的AMP支持,请向页面中添加ExportConstconfig={amp:true}
AMP First Page 1 2 3 4 5 6 // pages/about.js export const config = { amp: true }; export default function AboutPage(props) { return <h3>My AMP About Page!</h3>; }
Hybrid AMP Page 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // pages/hybrid-about.js import { useAmp } from 'next/amp'; export const config = { amp: 'hybrid' }; export default function AboutPage(props) { return ( <div> <h3>My AMP Page</h3> {useAmp() ? ( <amp-img width="300" height="300" src="/my-img.jpg" alt="a cool image" layout="responsive" /> ) : ( <img width="300" height="300" src="/my-img.jpg" alt="a cool image" /> )} </div> ); }
AMP Page Modes AMP Behavior with next export Adding AMP Components AMP社区提供了许多组件,使AMP页面更具交互性。您可以使用Next/Head将这些组件添加到页面中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // pages/hello.js import Head from 'next/head'; export const config = { amp: true }; export default function MyAmpPage() { return ( <div> <Head> <script async key="amp-timeago" custom-element="amp-timeago" src="https://cdn.ampproject.org/v0/amp-timeago-0.1.js" /> </Head> <p>Some time: {date.toJSON()}</p> <amp-timeago width="0" height="15" datetime={date.toJSON()} layout="responsive"> . </amp-timeago> </div> ); }
AMP Validation TypeScript Support Amp目前还没有内置的TypeScript类型,但是它在他们的路线图中。作为解决办法,您可以手动将这些类型添加到amp.d.ts中。
Static HTML export Limitation Multi Zones How to define a zone 没有与专区相关的API。您只需执行以下操作:
1.确保在你的应用程序中只保留你需要的页面,这意味着一个应用程序不能有来自另一个应用程序的页面,如果应用程序A有/blog,那么应用程序B就不应该拥有它。 2.确保添加资产前缀以避免与静态文件的冲突。
How to merge them 可以使用任何HTTP代理合并区域。 您现在可以使用dev作为本地开发服务器。它允许您轻松地为多个应用程序定义路由,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 { "version": 2, "builds": [ { "src": "docs/next.config.js", "use": "@now/next" }, { "src": "home/next.config.js", "use": "@now/next" } ], "routes": [ { "src": "/docs/_next(.*)", "dest": "docs/_next$1" }, { "src": "/docs(.*)", "dest": "docs/docs$1" }, { "src": "(.*)", "dest": "home$1" } ] }
对于生产部署,可以使用相同的配置并立即运行,以便立即使用Zeit进行部署。否则,还可以将代理服务器配置为使用一组路由(如上面的路由)进行路由。
Recipes 1.设置301重定向 2.只处理SSR和服务器模块 3.基于React-Material-UI-Next-Express-Mongoose-Mongodb的建筑 4.使用React-Material-UI-Next-MobX-Express-Mongoose-MongoDB-TypeScript构建SaaS产品
Contributing 请看我们的contributing.md
Authors Arunoda Susiripala (@arunoda) – ZEIT Tim Neutkens (@timneutkens) – ZEIT Naoyuki Kanezawa (@nkzawa) – ZEIT Tony Kovanen (@tonykovanen) – ZEIT Guillermo Rauch (@rauchg) – ZEIT Dan Zajdband (@impronunciable) – Knight-Mozilla / Coral Project