Next.js 实现原理系列(3):页面渲染

背景

这是 Next.js 实现原理系列的第 3 篇,承接之前对 Link 和 Router 的讨论,来看看页面渲染的原理。

本篇主要回答下面这个问题:

  • 在 Next.js 中,切换 Page 时,为什么页面上不变的部分也会被重新渲染?

搞懂了这个问题,也就能大致明白 Next.js 页面渲染的原理了。

注:本系列文章基于 Next.js v12.0.4 版本。

切换 Page 时,为什么页面上不变的部分也会被重新渲染?

你也许注意过,在 Next.js 中切换 Page 时,页面上即使是不变的部分(例如 header)也会被重新渲染,这一点和常规的 React SPA 完全不同。如下图所示:
请添加图片描述

上面这个例子使用的是 Next.js 的官方网站 https://nextjs.org,它本身就是使用 Next.js 搭建的。可以看到,如果你把 header 的背景色修改为黄色,再切换到另一个页面,header 的黄色就不见了,说明它被重新渲染过。

这不能不说有些令人意外。虽然看不到源码,但这两个页面显然使用的应该是同一个 header 组件,没有任何理由应该重新渲染一遍。为了确认这一点,我自己新建了一个 project 试了一下,发现如果有 pages/a.jspages/b.js 这两个 page,并且它们都引用了同一个组件 C,那么在 a 和 b 之间通过链接切换时,C 的确会重新渲染。

你可能会说,是因为 Next.js 在服务端渲染吧!并非如此,因为当你第一次访问这个网站的时候,拿到的 HTML 确实是在服务端渲染好的,但在进行后续的站内页面切换时,Next.js 采用的也是客户端渲染,换句话说和常规的 React SPA 应用没有区别(关于这一点可以参考我的另一篇文章:一箭双雕:浅谈 Next.js 页面导航(page navigation)原理)。如果你用 create-react-app 创建一个常规的 React SPA 应用,就绝对不会出现这样的事情。

当然了,Next.js 中并不是没有避免相同组件重复渲染的方法!只不过上面的例子没有使用而已。如果你希望 header 不要重复渲染,那么可以新建一个 pages/_app.js 文件:

// pages/_app.js

import React from 'react';
import Layout from '../components/Layout';

function MyApp({
     Component, pageProps }) {
   
  return (
  	
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
index.vue:201 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'type') at _callee$ (index.vue:201:1) at tryCatch (regeneratorRuntime.js:44:1) at Generator.eval (regeneratorRuntime.js:125:1) at Generator.eval [as next] (regeneratorRuntime.js:69:1) at asyncGeneratorStep (asyncToGenerator.js:3:1) at _next (asyncToGenerator.js:22:1) at eval (asyncToGenerator.js:27:1) at new Promise (<anonymous>) at eval (asyncToGenerator.js:19:1) at VueComponent.handleNodeClick (index.vue:227:1) _callee$ @ index.vue:201 tryCatch @ regeneratorRuntime.js:44 eval @ regeneratorRuntime.js:125 eval @ regeneratorRuntime.js:69 asyncGeneratorStep @ asyncToGenerator.js:3 _next @ asyncToGenerator.js:22 eval @ asyncToGenerator.js:27 eval @ asyncToGenerator.js:19 handleNodeClick @ index.vue:227 handleCurrentChange @ index.vue:197 invokeWithErrorHandling @ vue.runtime.esm.js:3971 invoker @ vue.runtime.esm.js:1188 invokeWithErrorHandling @ vue.runtime.esm.js:3971 Vue.$emit @ vue.runtime.esm.js:2874 eval @ element-ui.common.js:1116 eval @ vue.runtime.esm.js:4097 flushCallbacks @ vue.runtime.esm.js:4019 Promise.then(异步) timerFunc @ vue.runtime.esm.js:4044 nextTick @ vue.runtime.esm.js:4109 queueWatcher @ vue.runtime.esm.js:3346 Watcher.update @ vue.runtime.esm.js:3584 Dep.notify @ vue.runtime.esm.js:710 reactiveSetter @ vue.runtime.esm.js:4380 proxySetter @ vue.runtime.esm.js:5158 handleCurrentChange @ element-ui.common.js:1069 invokeWithErrorHandling @ vue.runtime.esm.js:3971 invoker @ vue.runtime.esm.js:1188 invokeWithErrorHandling @ vue.runtime.esm.js:3971 Vue.$emit @ vue.runtime.esm.js:2874 onPagerClick @ element-ui.common.js:547 invokeWithErrorHandling @ vue.runtime.esm.js:3971 invoker @ vue.runtime.esm.js:1188 original_1._wrapper @ vue.runtime.esm.js:7265
06-12

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值