【服务端渲染】Next.js 学习笔记

Next.js 学习

  • 基于React的服务器端渲染框架
  • 特点:
    • 默认服务端渲染,以文件系统为基础的客户端路由,没有路由配置文件
    • 代码自动分割使页面加载更快
    • 使用 ES6 module
    • 对 SEO 友好,提升手机及低功耗设备的性能,快速显示首页

文件系统的路由:

  • 创建 ./pages 文件夹,该文件夹只能存放页面级别的组件
  • 默认访问 pages/index.js 文件,其他的页面需要通过访问该路径,e.g. /test 来访问 pages/test.js 文件,或者 访问 pages/test/index.js 文件(推荐这种目录结构)

路由跳转:

通过组件实现:
import Link from 'next/link'

export const NextRoute = () => (
	<div>
		<Link href='/next-route/aaa'>
			<a style={{color: "red"}}>Teacher</a>
		</Link>
	</div>
)
  • 使用 Link 组件,添加 href 属性,表示需要跳转的路径
  • href 可以是一个字符串,也可以是 URL 对象,可以自动格式化生成 URL 字符串,{{pathname: '/next-route/aaa', query: {id: 11}} => '/next-route/aaa?id=11'
  • 不能直接在 Link 组件中写字符串,需要用一个标签包起来,可以是 <a>, <p>, <button>
  • Link 组件只能包含一个 React Element child
  • 不能直接给 Link 组件添加样式,因为 Link 是一个 HOC,可以给子元素设置样式
通过命名式路由实现:
import Router from 'next/router'

export const NextRoute = () => (
	<div>
		<span onClick={()=> Router.push('/next-route/bbb' }>Student</span>
	</div>
)
  • 也可以使用 URL 对象语法,e.g. Router.push({pathname: '/next-route/bbb', query: {id: 1}})

注意:
- 如果没有匹配到,默认会去找 pages/_error.js 中定义的组件
- 路由跳转不会向服务器发送请求页面的请求,只会请求 js 文件

组件:

普通组件:
  • 一般放在 ./components 文件夹下,然后在适当的页面引入并使用,不要放在 ./pages 下,因为组件不需要 url
布局组件:
  • 一般放在 ./layout 文件夹下,使用 props.children 属性

    import Mynav from '../components/Mynav'
    export const MyLayout = (props) => (
    	<div>
    		<Mynav></Mynav> // e.g. 包括两个 Link 用来导航
    		{props.children}
    	</div>
    )
    

    使用:

    import MyLayout from '../../layouts/MyLayout'
    export const NextRoute = () => (
    	<div>
    		<MyLayout>
    			<p>Hello World</p> // 作为 children 传递到 MyLayout 组件中
    		</MyLayout>
    	</div>
    )
    
全局布局组件:
  • 创建 _app.js,这样可以不用在每个页面中都单独引入布局组件

    import React from 'react'
    import App, { Container } from 'next/app'
    
    // 替换成自己的布局组件
    const Layout = (props) => (
    	<div className="layout">{props.children}</div>
    )
    
    // 使用模板
    export default class MyApp extends App {
    	render(){
    		const { Component, pageProps } = this.props
    		return (
    			<Container>
    				<Layout> // 布局组件
    					<Component {...pageProps}/> // 页面级别的组件
    				</Layout>
    			</Container>
    		)
    	}
    }
    

路由的参数查询

  • 使用 withRouter,这是一个 HOC,会将当前的路由对象绑定到组件的 props 属性上

  • 可以通过 props.router.query 获取路由的参数

    import { withRouter } from 'next/router'
    const Detail = (props) => (
    	<div>这是${props.router.query.id}号选手的详情</div>
    )
    export default withRouter(Detail)
    

浅层路由

  • 可以通过 Link 组件的 as 属性给路径起别名,e.g. 原始的 /next-route/user/detail?id=1 => /next-route/user/1

    <div>
    	<Link as={`/next-route/user/${item.id}`} href={`/next-route/user/detail?id=${item.id}`}>
    		<p>Detail</p>
    	</Link>
    </div>
    

服务端支持 Clean URLs:

  • 如果直接通过刷新使用别名后的地址是无法获取到对应的页面,可以通过服务端来支持浅层路由(Clean URLs)

  • 安装 express, 在项目的根目录创建 server.js

    const express = require('express');
    const next = require('next');
    
    const env = process.env.NODE_ENV;
    const dev = env !== 'production';
    const app = next({ dev }); // 创建一个 next 实例
    const handle = app.getRequestHandler(); // 得到用来处理请求的函数
    
    app.prepare() // 实例构建好之后
      .then(() => {
      	const server = express(); // 创建 express 服务器
      	// Default catch-all handler to allow Next.js to handle all other routes
      	server.all('*', (req, res) => handle(req, res));
    
      	server.listen(3000, (err) => { // 监听端口号
          if (err) {
          	throw err;
          }
          console.log(`[Express] Ready on http://localhost:3000`);
        });
      });
    
  • 修改 package.jsonscript

    "script": {
    	"dev": "node server.js",
    	"build": "next build",
    	"start": "NODE_ENV=production node server.js"
    }
    
  • 创建自定义路由,根据实际情况调整参数,并添加在 server.jsserver.get("*", ...) 之前:

    server.get('/teacher/:id', (req, res) => {
    	const actualPage = '/teacher/detail'
    	const queryParams = { id: req.params.id }
    	app.render(req, res, actualPage, queryParams)
    })
    
发布了4 篇原创文章 · 获赞 2 · 访问量 60

猜你喜欢

转载自blog.csdn.net/panpan0329/article/details/105318545