iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >React 模式之纯组件使用示例详解
  • 611
分享到

React 模式之纯组件使用示例详解

2024-04-02 19:04:59 611人浏览 安东尼
摘要

目录什么是纯组件纯组件解决了什么问题怎么使用纯组件CC: shouldComponentUpdate() 和 React.PureComponentFC: React.memo()你

什么是纯组件

纯组件(Pure Component)这概念衍生自纯函数。纯函数指的是返回结果只依赖于传入的参数,且对函数作用域外没有副作用的函数。这种函数在相同参数下,返回结果是不变的。纯函数的返回值能被安全缓存起来,在下次调用时,跳过函数执行,直接读取缓存。因为函数没有外部副作用,不执行函数对整个程序没有影响。

与纯函数类似,如果一个组件在 props 和 state 相同的情况下,每次 render 的结果都是相同的,那这个组件就是纯组件。也就是说,纯组件的 render 结果只依赖于 props 和 state,如果两次渲染中,props 和 state 是相同的,那它们的 render 结果也是一样的。

纯组件解决了什么问题

在理解纯组件有什么用处之前,先来看一下 React 如何更新组件。

React 在更新组件时,会从触发组件开始,递归地调用整颗子树的 render 函数,构建新的虚拟树。即使子组件的 props 和 state 没有变化,render 函数还是会被执行。

看这个例子:

const defaultMessage = "Hello!";
function Messager() {
  console.log("render in parent");
  const [messageInput, setMessageInput] = useState(defaultMessage);
  const [messageData, setMessageData] = useState({
    id: 0,
    message: "",
  });
  return (
    <div className="logger">
      <input
        value={messageInput}
        onChange={(e) => setMessageInput(e.target.value)}
      ></input>
      <button
        onClick={() =>
          setMessageData((preData) => ({
            id: preData.id + 1,
            message: messageInput,
          }))
        }
      >
        发送消息
      </button>
      <MessageText message={messageData.message} />
    </div>
  );
}
function MessageText(props) {
  console.log("render in child");
  return <div>最新消息:{props.message}</div>;
}

连续点击几次按钮:

父组件 Messager 由于状态更新,需要重新执行 render 函数来更新组件,这个是符合预期的。子组件 MessageText 中,第一次更新,由于 message 属性改变,也需要更新,这个也容易理解。

问题在后面几次更新:

  • 子组件的 props 没有变化,为什么执行了 render 函数?
  • render 函数执行了,是不是意味着 DOM 也更新了,只是我们看不出变化?
  • 组件在 props 没有变化时,绘制的视图都是不变的,能不能跳过 render 函数的执行?

让我一个一个来回答。

Q:为什么需要执行 render 函数?

A:你的组件可能使用了任何变量,包括全局变量、环境变量等,React 没有能力做到监听这些变量,这些变量的变化是 React 无法感知的。为了保证渲染的视图与数据是一致的,React 只能牺牲性能,在每次更新的时候,都去执行 render 函数,获取最新的 render 输出。

Q: 执行了 render 函数就一定会更新 DOM 吗?

A:不一定。render 函数的输出结果是 React 虚拟 DOM,执行了 render 函数会更新虚拟 DOM,但 React 足够聪明,能够比对出浏览器 DOM 需要更新的地方,让浏览器只进行必要的重绘。这也是 React 能够保证性能的重要手段。

Q:能避免不必要的 render 执行吗?

A:可以。如果是 class 组件(CC),你可以重写 shouldComponentUpdate() 方法或继承 React.PureComponent。如果是函数组件(FC),你可以使用 React.memo() 。这样能够避免不必要的 render 执行,在一定程度上提升页面的性能,尤其是当 render 函数内有复杂计算时。这也正是纯组件想要解决的问题。

怎么使用纯组件

CC: shouldComponentUpdate() 和 React.PureComponent

? 这一小节的内容基于 class 组件,FC 不适用。

React 组件更新前,会调用 shouldComponentUpdate(nextProps,nextState),当返回 true 时,组件就会 re-render。所以,你可以重写这个方法,当不希望组件更新时,返回 false

重写上面的 MessageText 组件:

class MessageText extends React.Component {
  shouldComponentUpdate(nextProps) {
    if (nextProps.message === this.props.message) {
      return false;
    }
    return true;
  }
  render() {
    console.log("render in child with message=" + this.props.message);
    return <div>最新消息:{this.props.message}</div>;
  }
}

这样,render 函数只会在 props.message 变化的时候才会被调用。当然,你可以自己决定哪些条件下跳过 render。

? shouldComponentUpdate 返回 false 时并不能保证跳过 render。React 后续可能会增加自己的判断,只把这个返回结果作为一种提示。所以这个方法应该只能被用于性能优化,不能作为逻辑依赖。

大部分时候,我们期望在 props 和 state 不变的时候,跳过 render,因为这经常导致不必要的更新。上面的例子只有一个属性,有点过于简单了,组件可能会多个 props 和 state,需要在 () 中穷举比较。

因为这种模式太过常见,React 提供了 React.PureComponent 类,你可以继承这个类,来实现纯组件的效果,即当 props 和 state 不变(浅比较)时,跳过 render。

class MessageText extends React.PureComponent {
  render() {
    console.log("render in child with message=" + this.props.message);
    return <div>最新消息:{this.props.message}</div>;
  }
}

FC: React.memo()

先回答一个普遍疑惑的问题。

Q:FC 是纯组件吗?或者无状态的 FC 是纯组件吗? A:并不是。从最上面的例子就可以看出来。无状态 FC 与纯组件是独立的概念,状态并不是影响纯组件的因素,关键在于组件函数除了 state 和 props 有没有外部依赖,对外部有没有影响。

Q:既然如此,怎么把 FC 改造成纯组件? A:很简单,用 class 重写组件并继承 React.PureComponent 就可以了。

说笑了,这年头,谁写 React 还用 class 啊。

然而,很遗憾,hooks 无法覆盖 shouldComponentUpdate() 的使用场景,FC 没有等效于 React.PureComponent 的写法。

不过,倒是可以使用 React.memo() 实现一个半吊子的纯组件。

const memorizedFC=React.memo(FC,arePropsEqual(preProps,nextProps)=>{
    // 返回true,跳过render
    // 返回false,执行render
})

React.memo() 把上次调用的结果保存在内存中,下次调用时,如果 arePropsEqual() 返回 true,那就直接使用上次的结果,不需要执行 FC。arePropsEqual 参数可选,默认使用浅比较。

利用 React.memo(), 把 MessageText 改造成纯组件 PureMessageText

function MessageText(props) {
  console.log("render in child with message=" + props.message);
  return <div>最新消息:{props.message}</div>;
}
const PureMessageText = React.memo(MessageText);

注意 React.memo() 并不等效于 React.PureComponent,前者只能比较 props,对于状态导致的更新,FC 依然会执行。这也是为什么说是“半吊子纯组件”。

如果 FC 无状态,那 React.memo() 就可以等效于 React.PureComponent 了。既然如此,对有状态 FC,可以利用状态上移把 state 转为 props,再应用 React.memo(), 实现纯组件的效果。

所以,绝大多数情况下,React.memo() 已经足够了。

你可能并不需要纯组件

了解纯组件的概念,以及它对 React 应用性能的影响,对一个开发者有很大帮助,但这并不意味着你需要经常使用它。

React 提供了良好的性能保证,大部分情况下,你的应用不会有性能上的问题,使用纯组件反而增加理解成本。

即使出现了性能问题,一些通用的性能优化手段可能更有效果。只有当性能瓶颈出现在特定组件的 render,并且这个组件可以被改造成纯组件时,这个措施才会有效果。

以上就是React 模式之纯组件使用示例详解的详细内容,更多关于React 纯组件模式的资料请关注编程网其它相关文章!

--结束END--

本文标题: React 模式之纯组件使用示例详解

本文链接: https://www.lsjlt.com/news/165954.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • React 模式之纯组件使用示例详解
    目录什么是纯组件纯组件解决了什么问题怎么使用纯组件CC: shouldComponentUpdate() 和 React.PureComponentFC: React.memo()你...
    99+
    2022-11-13
  • Java设计模式之组合模式的示例详解
    目录定义原理类图案例需求方案分析总结定义 组合模式,又叫部分整体模式,它创建了对象组的数据结构(将对象组合成树状结构,用来表示部分整体的层级关系)组合模式使得用户对单个对象和组合对象...
    99+
    2022-11-13
  • Flutter之 ListView组件使用示例详解
    目录ListView的默认构造函数定义默认构造函数ListView.builder ListView.separated固定高度列表ListView 原理实例:无限加载列表...
    99+
    2022-11-13
    Flutter ListView组件 Flutter ListView
  • 使用 React Hooks 重构类组件的示例详解
    目录1. 管理和更新组件状态2. 状态更新后的操作3. 获取数据4. 卸载组件时清理副作用5.  防止组件重新渲染6. Context API7. 跨重新渲染保留值8. 如...
    99+
    2022-11-13
  • Java设计模式之单例模式示例详解
    目录0.概述1.饿汉式1.1 饿汉式单例实现1.2 破坏单例的几种情况1.3 预防单例的破坏2.枚举饿汉式2.1 枚举单例实现2.2 破坏单例3.懒汉式4.双检锁懒汉式5.内部类懒汉...
    99+
    2022-11-12
  • React特征学习之Form格式示例详解
    目录Form 样式React hookForm 样式 首先来看一个简单Form, 式样如下 import * as React from 'react'; const LoginFo...
    99+
    2022-11-13
  • Hello React的组件化方式之React入门小案例演示
    目录React初体验Hello React案例演练Hello React案例升级Hello React的组件化组件化的方式数据依赖事件绑定其他案例练习电影列表展示计数器的案例Reac...
    99+
    2022-11-13
    Hello React案例 React入门 Hello React组件化
  • React路由拦截模式及withRouter示例详解
    目录一、路由拦截二、路由模式三、withRouter一、路由拦截 在前面两篇 路由博客基础上,我们将ReactRouter.js的我的profile路由设置成路由拦截的: <R...
    99+
    2022-11-13
    React路由拦截模式withRouter React路由
  • Java设计模式之享元模式示例详解
    目录定义原理类图案例需求方案:享元模式分析总结定义 享元模式(FlyWeight Pattern),也叫蝇量模式,运用共享技术,有效的支持大量细粒度的对象,享元模式就是池技术的重要实...
    99+
    2022-11-13
  • Java设计模式之外观模式示例详解
    目录定义案例需求方案:外观模式实现分析总结定义 外观模式为多个复杂的子系统,提供了一个一致的界面,使得调用端只和这个接口发生调用,而无须关系这个子系统内部的细节 案例 需求 看电影的...
    99+
    2022-11-13
  • Java设计模式之策略模式示例详解
    目录定义结构UML类图UML序列图深入理解策略模式策略和上下文的关系策略模式在JDK中的应用该策略接口有四个实现类策略模式的优点策略模式的缺点策略模式的本质在讲策略模式之前,我们先看...
    99+
    2022-11-13
  • react使用useImperativeHandle示例详解
    目录1.前言2.useImperativeHandle初探3.获取元素的几种方式3.1 useRef:获取组件内部元素3.2 forwardRef:父组件获取子组件内部的一个元素3....
    99+
    2022-11-13
  • React元素与组件的区别示例详解
    目录从问题出发元素与组件元素组件问题如何解决自定义内容第一种实现方式第二种实现方式第三种实现方式从问题出发 我被问过这样一个问题: 想要实现一个 useTitle 方法,具体使用示例...
    99+
    2022-11-13
    React元素组件区别 React元素组件
  • react组件实现无缝轮播示例详解
    目录正文无缝轮播实现思路构思使用时代码结构Carousel组件CarouselItem组件完善组件完成小圆点正文 需求是做一个无缝轮播图,我说这不是有很多现成的轮子吗?后来了解到他有...
    99+
    2022-11-13
    react 组件无缝轮播 react 无缝轮播
  • 详解React中组件之间通信的方式
    一、是什么 我们将组件间通信可以拆分为两个词: 组件 通信 回顾Vue系列的文章,组件是vue中最强大的功能之一,同样组件化是React的核心思想 相比vue,...
    99+
    2022-11-12
  • Java设计模式之原型模式的示例详解
    目录定义案例需求方案一方案二对比分析总结 定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 即实现了一个原型接口,该接口用于创建当前对象的克隆,当直接创建对象的代...
    99+
    2022-11-13
  • Java设计模式之桥接模式的示例详解
    目录定义案例需求方案一方案二对比分析总结定义 桥梁模式是对象的结构模式。又称为柄体(Handle and Body)模式或接口(Interface)模式。桥梁模式的用意是&ldquo...
    99+
    2022-11-13
  • React 路由使用示例详解
    目录Router简单路由嵌套路由未匹配路由路由传参数索引路由活动链接搜索参数自定义行为useNavigate参考资料Router react-router-dom是一个处理页面跳转的...
    99+
    2022-11-13
  • Java之dao模式详解及代码示例
    什么是dao模式?DAO(Data Access Object)顾名思义是一个为数据库或其他持久化机制提供了抽象接口的对象,在不暴露底层持久化方案实现细节的前提下提供了各种数据访问操作。在实际的开发中,应该将所有对数据源的访问操作进行抽象化...
    99+
    2023-05-30
    java dao设计模式 ava
  • react组件memouseMemouseCallback使用区别示例
    目录正文memo使用useMemo使用useCallback使用正文 memo用来优化函数组件的重复渲染行为,针对的是一个组件 useMemo返回一个memoized的值 本质都是用...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作