IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 了解 React 重渲染机制 -> 正文阅读

[JavaScript知识库]了解 React 重渲染机制

核心概念

首先,要贯彻一个思想:

唯有 State 改变才会引入 React 重渲染

也就是说,其实 propscontext 的改变并不会导致重渲染。其实是他们的父级组件 state 改变了,导致所有后代组件都进行了一次重渲染。考虑一个这样的组件结构:

import React from "react";

function App() {
  return (
    <>
      <Counter />
      <footer>
        <p>Copyright 2022 Big Count Inc.</p>
      </footer>
    </>
  );
}

function Counter() {
  const [count, setCount] = React.useState(0);

  return (
    <main>
      <BigCountNumber count={count} />
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </main>
  );
}

function BigCountNumber({ count }) {
  return (
    <p>
      <span className="prefix">Count:</span>
      {count}
    </p>
  );
}

export default App;

count 变量改变时,Couter 的后代 BingCountNumber 也会被重新渲染。但父级组件 App 是不会被重新渲染的,也包括 App 的后代之一 footer

React 渲染机制

我们可以把每次渲染都当作 React 在拍一张照片(snapshot),这张照片描述了最后 html 生成的结构。当 count 变量改变时,React 会重新拍摄一张照片并进行比对,然后只更新有变化的地方

但如上节所说,只要某个组件的 state 发生变化,那么不管其后代组件有没有 props,React 会把它们都更新个遍。

为什么 React 要这么设计呢?因为,React 并不知道你的组件是不是「每次渲染都能输出一样的结果」,就比如:

function CurrentTime() {
  const now = new Date();
  return <p>It is currently {now.toString()}</p>;
}

你会发现,这个组件无论 props 是什么,每次渲染的结果都是不一样的。这种组件被称为「副作用组件」,与之相反的概念是「纯组件」,也就是在相同输入下,输出也相同的组件。

React 开发团队在渲染结果方面一直都是秉承小心谨慎的态度,宁愿牺牲一些性能也不愿意冒风险渲染出不正确的页面(比如 React 在捕获到错误的时候会默认白屏)。

创建纯组件

如果我们可以自信地认为自己写的组件就是纯组件,每次渲染输出的结果都是相同的。那么可以使用 React.memo 方法包装起来:

function Decoration() {
  return <div className="decoration">??</div>;
}
export default React.memo(Decoration);

这样在它的父级组件的重渲染的时候,只要 props 没变化,那么这个组件就不会被重新渲染。

那为什么 React 不把这个行为内置到框架中呢?这个逻辑感觉不是更直观,更理所当然吗?原因是性能

作为开发者我们总是高估了「重渲染」的成本,其实 React 经过这么长时间的升级,已经把重渲染这一步优化得很好了。如果一个组件,没有很耗时的计算,但却有很多 props 依赖,那么其实新旧 props 的对比的性能损耗反而会比重新渲染更高。

反之,如果一个组件拥有比较复杂的计算逻辑,但 props 数量不多,那还是建议使用 React.memo 来减少无谓的计算。

不过,这个现象可能会在未来被改变,React 官方已经在测试「自动 memo」相关的功能了。详情可以看黄玄的演讲

Context 的影响

说完 props,再来说说 context:

const GreetUser = React.memo(() => {
  const user = React.useContext(UserContext);
  if (!user) {
    return "Hi there!";
  }
  return `Hello ${user.name}!`;
});

其实 context 可以被看作隐性的 props。也就是说,上面的代码可以看成下面这样:

const GreetUser = React.memo(({ user }) => {
  if (!user) {
    return "Hi there!";
  }
  return `Hello ${user.name}!`;
});

那么这个组件的重渲染规则就和上面说的 props 如出一辙。

调试

使用 React Developer Tools 可以调试重渲染现象。在开发者工具中选择 Profiler 面板,可以录制一段活动来分析组件的详细渲染情况。

或者可以实时高亮被重渲染的组件。

例外

有时候可能会碰到一种情况:明明包裹了 React.memo 并且 props 也「没有改变」,子组件还是被重渲染了:

function App() {
  const dog = {
    name: "Spot",
    breed: "Jack Russell Terrier",
  };
  return <DogProfile dog={dog} />;
}

这是因为 React.memo 对于 props 的比较实际上是浅比较,也就是说如果 props 是一个 Object,那只会比较其内存的引用地址。

在 👆 上面的那个例子中,每次 App 渲染都会创建一个新的 dog 对象并传入 DogProfile,那么不管 DogProfile 有没有包裹 React.memo,都会进行重渲染。

总结

  1. 只有 state 变化会导致 React 组件重渲染。
  2. 使用 React.memo 创建纯组件
  3. 不要过度优化
  4. React.memo 只对 props 进行浅比较

本文源自:https://www.joshwcomeau.com/react/why-react-re-renders/

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 21:06:34  更:2022-10-22 21:06:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/11 17:06:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码