React
的SSR
框架- 渲染有三种方式: BSR(客户端渲染,Browser Side Render),SSG(静态页面生成,Static Site Generation),SSR(服务端渲染,Server Side Render)
- 需要注意的是如果页面中有用js控制的部分(例如条件渲染),在SSR的时候不会直接渲染成DOM元素,虽然也能导出成静态HTML,但是仍然是前端js来控制的
基础配置
1 | npx create-next-app@latest # 初始化项目 |
next.config.js
- 每次修改必须重启应用
- 在
.env
中设置的环境变量默认不会在后端渲染中被前端看到,但是如果以NEXT_PUBLIC_
开头的环境变量,是能看到也能被前端直接使用的
1 | module.exports = { |
路由
路由定义
- 路由定义默认是根据pages文件夹下的文件名来的
1 | pages/blog/first-post.js → /blog/first-post |
路由常用方法
1 | import { useRouter } from 'next/router'; |
路由事件
包括:routeChangeStart、routeChangeComplete、routeChangeError、beforeHistoryChange、hashChangeStart、hashChangeComplete
页面组件
- 通过变量渲染html,需要用
<div dangerouslySetInnerHTML={{__html = ''}}
Layouts
全局定义页面的layout
所有页面都相同的layout可以这样做
1
2
3
4
5
6
7
8
9
10// pages/_app.js
import Layout from '../components/layout'
export default function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}如果不是所有页面的layout都相同,可以参考官方文档
Head
可以在
Head
里面插入全局的js,例如google analytics代码:1
2
3
4
5
6
7
8
9
10
11<Head>
<script
dangerouslySetInnerHTML={{
__html: `[google analytics tracking code here]`
}}
/>
// 字体优化,能够在编译阶段就优化字体,这样在打开页面不会因为要获取字体文件而闪一下
</Head>
Image
- 需要在
next.config.js
中配置图片域名images.domains
- 可以设置width、height、quality、priority、responsive自动修改图片显示大小
- 但是毕竟是后端js程序在进行转换,不如直接使用
cloudinary
这样的服务速度快功能多 - 如果图片存储在第三方需要添加配置
images: loader: 'imgix'
- width和height必填,除非
layout=fill
1 | import Image from 'next/image' |
使用svg作为component
- 和其他框架一样,都是用
npm install @svgr/webpack --save-dev
- 需要做如下配置:
1 | // next.config.js 添加如下配置 |
Link
1 | <Link href=''> |
后端渲染SSR
- 在组件加载前就从接口获取数据,才能实现后端渲染,而不是前端去调用API
- 需要注意的是通过服务端获取的props,必须直接传递到html中去,不要用useEffect等去传递给另外一个变量,那样就不会直接渲染到HTML中去了,浏览网页源代码发现他们只是在一个变量上,对SEO十分不友好
getServerSideProps
和getInitialProps
都无法用在404页面上,如果是404页面只能在componentDidMount
或者useEffect(() => {}, [])
里面去请求获取数据了,官方说明- 判断当前是否是后端渲染有一个简单的办法,那就是
typeof window === undefined
1 | class MyComponent extends React.Components { |
禁用后端渲染NoSSR
- 如果要针对某个component或者某个html设置为不需要后端渲染或者某个组件前后端渲染本身就不一样导致报错
Hydration failed because the initial UI does not match what was rendered on the server.
那么可以这样做
1 | // 新建一个component,NoSsr.tsx |
Hook
获取window size
1 | // hooks/useWindowResize.js |
其他特性
动态引入模块
1 | const DynamicComponent = dynamic(() => import('../components/hello')) |
国际化i18N
- nextjs的国际化支持很棒,只要设定好需要哪些语言,就只要在切换语言的时候指定语言,而不需要更改页面中其他的地方
- 支持通过域名来切换语言,或者通过path前缀来切换语言
1 | // next.config.js |
TroubleShooting
- pages with
getServerSideProps
can not be exported. 需要将package.json
中的build
命令中的next export
去掉,它和getServerSideProps
不兼容 - getServerSideProps不起作用: 它只能做用于page,不能直接作用于component
- 初始进入admin太慢: 是因为js太大,尝试给nginx加上gzip试试
- rewrites会render两次: 我也不清楚原因,目前正在论坛上问https://github.com/vercel/next.js/discussions/27985
- 生成的静态页面会有__next_data__字段存储着所有的props信息:这样页面上其实就有两份数据了,但是看作者的意思是所有的后端渲染都会这样做的,无法去掉https://github.com/vercel/next.js/discussions/13418,所以最好用graphql等或者其他方式只保留需要的字段