Next.js全解

3,295 阅读3分钟

定位

Next.js是node.js全栈框架

  1. css-in-js
  2. 页面预渲染+ssr(服务端渲染)
  3. 前后端同构(代码同时运行在两端)
  4. Node.js 10.13以上,支持React/Typescript

弱项

完全没有提供数据库相关的功能,可自行搭配Sequelize或TypeORM,没有提供测试相关的功能,可自行搭配Jest或Cypress

创建项目

npm init next-app myAppName//创建项目

Link快速导航

用法:把<a href='xxx'>跳转</a>改成<Link href='xxx'><a>点击跳转</a></Link>

优点页面不会刷新,用AJAX请求新页面内容,不会请求重复的HTML/CSS/JS,自动在页面中替换内容,省去请求和解析,所以速度极快

同构代码

代码运行在两端
在组件中写了一句console.log('执行了')
node控制台和浏览器控制台都会输出这句话
不是所有代码都会运行,有些需要用户触发,不是所有api都能用,比如window在node里报错

全局配置

自定义head

在page/_app.js中可以加入全局的样式,并且引入head 配置全局的meta/title等内容

import '../styles/globals.css'
import Head from 'next/head'

function MyApp({ Component, pageProps }) {
  return (
    <>
      <Component {...pageProps} />
      <Head>
        <title>我的blog</title>
        <link rel="icon" href="/favicon.ico" />
        <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no, viewport-fit=cover" />
      </Head>
    </>
  )
}

export default MyApp

局部CSS

import React from 'react'

export default function X() {
    return (
        <>
            <div>
                <h1>这是第一篇博客</h1>
                <hr />
                <a href="/">回到首页</a>
            </div>
            <style jsx>
                {`
                h1{
                    color:black;
                }
                `}
            </style>
        </>
    )
}

绝对引用

创建jsconfig.json文件,配置

"compilerOptions": {
	"baseUrl": "."
}

style.module.css

可以在style文件中创建demo.module.css,然后在要使用的地方引入这个文件使用即可

import React from 'react'
import styles from 'styles/demo.module.css'

export default function X() {
    return (
        <>
        	<div className={styles.wrapper}>我是wrapper</div>
            <div className={styles.content}>我是内容</div>
        </>
    )
}

next-images

假设我们现在要用到图片,但又不想把图片放到public中直接引用,而是引用其它目录的图片,我们可以使用插件
首先新建next.config

yarn add next-images//安装
const withImages = require('next-images')
module.exports = withImages({
    webpack(config, option) {
        return config
    }
})

Next.js API

实际开发中我们需要请求/user/shops等API
返回的内容是JSON格式的字符串,我们可以在page/api/目录创建文件返回对应的数据
该代码只运行在node.js里

import { NextApiRequest, NextApiResponse } from "next"

export default (req: NextApiRequest, res: NextApiResponse) => {
    res.statusCode = 200
    res.setHeader('Content-Type', 'application/json')
    res.write(JSON.stringify({ name: '我的名字' }))
    res.end()
}

next中的三种渲染

BSR(客户端渲染)

通过前端发ajax的方式获得数据进行渲染,这是我们常用的渲染方式,这里就不多做赘述了
缺点:白屏,seo不友好。
但是需要注意的是:在next中会渲染2次,后端1次(生成html),前端一次(绑定事件,用于确保前后端渲染结果一致)

const PostsIndex: NextPage = () => {
    const [posts, setPosts] = useState<Post[]>([])
    useEffect(() => {
        axios.get('api/v1/posts').then(res => {
            setPosts(res.data)
        })
    }, [])
    return (
        <div>
            {posts.map(item => <ul key={item.id}>
                <li>{item.title}</li>
                <li>{item.content}</li>
                <li>{item.date}</li>
            </ul>)}
        </div>
    )
}

SSG (静态页面生成)

使用getStaticProps提供数据
动态内容静态化,下面这种写法会在我们打包的时候生成一个静态页面给用户下载
next会帮我们生成html(含有静态内容,用于用户直接访问)/js(含有静态内容,用于快速导航)/json(含有数据,跟js合成新页面) 注意哦:前端也可以拿到这个数据,从script中拿
优点:无白屏,有利于seo。

const PostsIndex: NextPage<Props> = (props) => {//打包的时候会生成新的html内容
    const { posts } = props
    return (
        <div>
            <h1>文章列表</h1>
            {posts.map(item => <p key={item.id}>{item.title}</p>)}
        </div>
    )
}

export default PostsIndex;

export const getStaticProps: GetStaticProps = async () => {//会在打包的时候讲数据传递过去
    const posts = await getPosts()
    return {
        props: {
            posts
        }
    }
}

升级版SSG
添加路由,不同添加不同内容,不刷新页面

const PostsShow: NextPage<Props> = (props) => {
    const { posts } = props
    return (
        <div>
            文章详情
            <h1>{posts.title}</h1>
            <p>{posts.content}</p>
            <p>{posts.date}</p>
        </div>
    )
}
export default PostsShow;

export const getStaticPaths = async () => {//定义路由表
    const posts = await getPosts()
    return {
        paths: posts.map(item => {
            return { params: { id: item.id } }
        }),
        fallback: true
    }
}
export const getStaticProps: GetStaticProps = async ({ params }: any) => {
    const id = params.id//拿到路由传递的参数,去获得对应的参数
    const posts = await getPostById(id)
    return {
        props: {
            posts
        }
    }
}

SSR (服务器渲染)

使用getServerSideProps(content)
在每次请求时重新渲染,通过模板引擎替换内容,返回新的html页面
服务段渲染(SSR) 解决白屏问题,seo问题,可以生成用户相关内容(不同用户展示不同结果)

const Index: NextPage<Props> = (props) => {
  console.log('props.browser')
  console.log(props.browser)
  return (
    <div>
      <h1>你的浏览器是:{props.browser.name}</h1>
    </div>
  )
}

export default Index;

export const getServerSideProps: GetServerSideProps = async (ctx) => {
  const ua = ctx.req.headers['user-agent']
  const result = new UAParser(ua)
  console.log(result)
  return {
    props: {
      browser: result.getBrowser()
    }
  }
} 

如何选择渲染方式