共计 3159 个字符,预计需要花费 8 分钟才能阅读完成。
最近在一个资讯类的我的项目中用了 Next.js 服务端渲染,体验了一把服务端渲染的速度,首屏直出,渲染速度 666。
服务端渲染
在之前前后端没拆散的时候,前端简略写一下 HTML 模版,后端通过诸如 Php、Java 等各种模版引擎把动态页面解决成动静模版渲染进去,那个时候就是服务端渲染了。但这样好麻烦,历史车轮滚滚向前,单页面利用的时代,后端只提供接口,不再负责模板的解决。再起初为了解决 SEO 的问题,顺带首屏渲染的问题,总不能再回到前后端不拆散的年代吧,所以就是前端 er 本人抉择的路,跪着也要走下,Vue 的 Nuxt.js,React 的 Next.js 等 SSR 框架应运而生。
咱们平时宽泛应用 Vue、React 在客户端渲染,服务端返回了一个空的 HTML 模版,而后外部加载 JS,生成并操作 Dom,最初由浏览器渲染出页面,这样一系列的动作下来首屏加载会显的慢了不少。另外因为是个空的页面,爬虫无奈辨认,不利于 SEO,在浏览器中右键查看源码,能够看到页面是个空的 HTML。
服务端渲染(SSR),服务端间接返回了 HTML,浏览器显示即可,无需期待 JavaScript 实现下载且执行才显示内容,不仅渲染速度大大放慢,更利于搜索引擎的爬取,右键查看源码能够看到稀稀拉拉的 HTML 标签。
长处
- 更快的首屏加载速度
- 更敌对的 SEO
毛病
- 减少了保护老本
- 我的项目部署比单页面利用简单
Next.js 根本应用
路由零碎
pages 目录路由
- Next.js 的路由零碎基于文件门路主动映射,pages 目录内的文件会被主动解决成路由,所以通常 pages 下咱们只搁置页面路由的文件,其它组件不要放到 pages 目录上面。比方在 pages 目录上面创立了 login.js 和 register.js,那么路由就对应 /login 和 /register。
- 同样,多级路由也是相似的解决。例如在 pages 下创立了 user 目录,user 下创立 login 和 register 文件。/user/login 对应 login 文件,/user/register 对应 register 文件。
Next.js 的路由零碎使咱们不必再去关怀路由,正当在 pages 建设目录。
动静路由
- Next.js 也反对反对动静路由,在文件前携带 [param],例如
pages/post/[pid].js
,会匹配到海报详情页面 /post/pid。 -
预约义的 API 路由优先于动静 API 路由
- pages/post/create.js,将匹配 /post/create
- pages/post/[pid].js`,将匹配 /post/1, 但不匹配 /post/create
路由跳转与传参
next 提供了两种形式,别离是导航式路由 next/link 和 编程式 next/router
-
Link
href 为必须属性,可传递对象
<Link href="/about?name=jackylin"> <Link href={{pathname: '/article', query: { type: active} }}>
-
编程式导航 next/router
和 react hooks 中的 useHistory 用法一样
import {useRouter} from 'next/router' const router = useRouter() //: 1 router.push(`/article/${c.queueId}`) //: 2 router.push({ pathname: '/publish', query: { contentId: c.contentId, status: active } })
路由参数获取
Next.js 只能通过 query 来传递参数,不能应用 params。
useRouter 或 getServerSideProps 办法内都能够拿到 query 参数
import {useRouter} from 'next/router'
const {query} = useRouter()
query.cid //: 获取 cid 参数
这种动静路由的参数通过 query 能够获取到,在 getServerSideProps 办法内也能够通过 params 获取
router.push(`/article/${c.queueId}`)
css
Next.js 反对 Css Module 和 Css-in-JS 这两种形式,二者自带款式隔离。
动静导入
Next.js 同样反对和 React 客户端一样的 ES2020 import() 语法来实现导入,在 React 单页面我的项目外面,Webpack 解析到该语法时会主动进行代码宰割。在 Next.js 外面,还能够应用 next/dynamic
来动静导入组件,它们将在客户端懒加载。通过动静导入,对于一些不须要在服务端渲染的组件能够应用 dynamic 来解决。
const BreadCrumb = dynamic(() => import('@/components/ui/BreadCrumb'))
服务端申请 getServerSideProps
export async function getServerSideProps(context) {
return {props: {}, // will be passed to the page component as props
}
}
- getServerSideProps,次要用于在服务端申请数据,比方咱们列表的的首屏数据,像列表下一页的数据咱们则能够放到客户端去获取。context 参数外面蕴含路由参数等对象。
- 因为 getServerSideProps 是在服务端进行的申请,所以相干的 log 信息在终端能力看到,Network 面板外面是看不到申请状况包含 console 信息。
- getServerSideProps 返回数据后,Next.js 会把这些数据写到 HTML 源 码外面,即
window.__NEXT_DATA__.props
,这样就实现了把数据传送到客户端,客户端有了这些数据,比方能够拿着window.__NEXT_DATA__.props
外面的数据初始化 React 组件的 props 等。在 console 里输出__NEXT_DATA__
, 你就能看到 Next.js 在页面中封装了什么数据。
其它
- 全面兼容最新 React 17 版本
- 链接跳转应用 Link,防止应用编程式导航,有利于 SEO。
- Next.js 自带 Image 组件,主动优化图像,极大改善用户体验。
- 能够自定义 document 页面 404 页面、500 页面等。当 Next.js 捕捉到谬误时,不论是接口谬误还是代码运行时的谬误,Next.js 服务外部会对立转化并抛出 500 异样。
- 官网文档
服务端渲染常见问题
最初呢总结一下 Next.js 应用中遇到的问题,欢送各路侠客补充。
useEffect 的留神点
服务端渲染时拿不到屏幕、元素宽低等尺寸信息,不要让元素的显示依赖于 useEffect 外面的设施宽高、dom 地位计算。
useEffect(() => {
//: 谬误示例
//: 服务端渲染的时候拿不到设施宽度 deviceWidth 所以 isDesktop 的值不会扭转
deviceWidth > 960 && (isDesktop = true)
, [])
return (
<>
{isDesktop ? (<div>pc</div>) : null}
</>
)
一个响应式的页面,pc 端显示 HeaderBar 组件,m 端不显示,如何解决?
在客户端渲染的状况下,判断一下设施类型即可。然而在服务端渲染,在哪里判断设施类型呢?useEffect?不能在外面判断。
计划有二:
- 采纳客户端渲染的解决形式。应用 next/dynamic 动静导入 HeaderBar 组件,这样 HeaderBar 组件将在客户端进行渲染,其它元素仍然还是在服务端进行渲染。
- 仍然采纳服务端渲染的解决形式。通过 css 的媒体查问,在 m 端对 HeaderBar 进行
display:none
,这也是一种解决方法。