https://nextjs.org/
一个轻量级的 React 服务端渲染应用框架。
在线演示: https://next-new.now.sh
源码示例: https://github.com/jinven/next-demo
1
| npm install --save next react react-dom
|
1 2 3 4 5 6 7 8
| { "scripts": { "dev": "next", "build": "next build", "start": "next start" } }
|
目录约定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| . ├── .next/ // 默认的 build 输出目录 ├── components/ // 自定义组件 ├── config/ ├── config.js // 配置 ├── pages // 页面目录,里面的文件即路由 ├── pages/index.js // 首页 ├── pages/_app.js // 所有页面的根页面,相当于 layout ├── pages/_document.js // HTML 文件结构,包括 html、head、body ├── pages/***.js // 自定义页面,页面名称就是url路由名称 ├── pages/api/***.js // api目录,如:/api、/api/user、/api/user/1 ├── pages/***/***.js // 二级及多级目录,如:/user/1、/post/blog、/post/blog/1 ├── public // 全局文件目录,生成时会复制到生成目录,如 ico ├── static // 自定义静态文件目录 ├── styles // 自定义样式文件目录 ├── utils // 自定义帮助文件目录 ├── next.config.js // 合并到 webpack 的配置文件,可配置路由等 ├── server.js // 自定义服务启动文件 └── package.json
|
首页
1 2 3 4 5
| function HomePage() { return <div>Welcome to Next.js!</div> } export default HomePage
|
getInitialProps
服务端运行执行,可异步执行,返回对象到页面的 props,只能在 pages 页面中,不能在子组件
参数:
pathname
- URL 的 path 部分
query
- URL 的 query 部分,并被解析成对象
asPath
- 显示在浏览器中的实际路径(包含查询部分),为String类型
req
- HTTP 请求对象 (只有服务器端有)
res
- HTTP 返回对象 (只有服务器端有)
jsonPageRes
- 获取数据响应对象 (只有客户端有)
err
- 渲染过程中的任何错误
1 2 3 4 5 6 7 8 9 10 11
| import fetch from 'isomorphic-unfetch' function HomePage({ stars }) { return <div>Next stars: {stars}</div> } HomePage.getInitialProps = async ({ req }) => { const res = await fetch('https://api.github.com/repos/zeit/next.js') const json = await res.json() return { stars: json.stargazers_count } } export default HomePage
|
CSS支持
styled-jsx
样式只会在当前组件生效
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
|
CSS-in-JS
1 2 3 4
| function HiThere() { return <p style={{ color: 'red' }}>hi there</p> } export default HiThere
|
css插件
scss
1
| npm install --save @zeit/next-sass node-sass
|
1 2 3 4
| .example { font-size: 52px; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| const withSass = require('@zeit/next-sass') module.exports = withSass({ cssModules: true })
import css from '../styles/scss.scss' export default () => ( <div> <h1 className={css.example}>scss</h1> </div> )
|
动态路由
- pages/post/[参数名称].js
- pages/post/[参数名称1]/[参数名称2].js
1 2 3 4 5 6 7 8
| import { useRouter } from 'next/router' const Post = () => { const router = useRouter() const { pid } = router.query return <p>Post: {pid}</p> } export default Post
|
影子路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { useEffect } from 'react' import { useRouter } from 'next/router'
function Page() { const router = useRouter() useEffect(() => { router.push('/?counter=10', null, { shallow: true }) }, []) useEffect(() => { }, [router.query.counter]) } export default Page
|
自定义服务启动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const { createServer } = require('http') const { parse } = require('url') const next = require('next') const port = parseInt(process.env.PORT, 10) || 3000 const dev = process.env.NODE_ENV !== 'production' const app = next({ dev }) const handle = app.getRequestHandler() app.prepare().then(() => { createServer((req, res) => { const parsedUrl = parse(req.url, true) const { pathname, query } = parsedUrl console.log('server.js') if (pathname === '/a') { app.render(req, res, '/a', query) } else if (pathname === '/b') { app.render(req, res, '/b', query) } else { handle(req, res, parsedUrl) } }).listen(port, err => { if (err) throw err console.log(`> Ready on http://localhost:${port}`) }) })
|
serverless
1 2 3 4
| module.exports = { target: 'serverless', }
|