前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React 性能优化实践

React 性能优化实践

作者头像
桃翁
发布2019-12-20 16:49:15
1.5K0
发布2019-12-20 16:49:15
举报
文章被收录于专栏:前端桃园前端桃园

你可能已经注意到 React Hook 中有一个名为 useMemo 的奇怪的钩子。这个奇怪的钩子意味着什么,它的作用是什么?重要的是,它是怎样为你提供帮助的?

首先,稍微回顾一下 JavaScript 的相等性。

引用比较

你可能还记得 Javascript 如何比较对象?。当我们进行相等性比较时,会有一些棘手的结果:

代码语言:javascript
复制
{} === {} // false

const z = {}
z === z // true

React 用 Object.is 来比较组件,但是得到的结果与使用 === 相似。所以当 React 检查组件中的改变时,它可能会发现一些我们不会真正考虑的东西。

代码语言:javascript
复制
() => {} === () => {} // false
[] === [] // false

这种比较检查将会导致某些预期之外的 React 重新渲染。如果重新渲染是一些代价高昂的操作,则可能会降低性能。如果一部分需要进行重新渲染,则它将重新渲染整个组件树。因此 React 发布了 memo 来解决这个问题。

Memoization

有一个非常花哨的术语 memoizationmemoization 是一种“优化技术”,它传递了一个复杂的函数来进行记忆。在 memoization 中,当随后传递的参数相同时,它会记住结果。例如有一个计算 1 + 1 的函数,它将返回结果 2。但是如果它使用 memoization,则下次再通过该函数运行 1 + 1 时,它不会再次进行运算,而只会记住答案是 2,从而无需执行加法函数。

在 React 中,memoization 可以优化我们的组件,避免在不需要时进行复杂的重新渲染。例如可以用 React.memo 对程序进行优化,它就像一个纯组件一样,可以包装你的组件。但是 useMemo 的用法有些不同。

在官方的React文档中,useMemo 是这样子的:

代码语言:javascript
复制
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

useMemo 接受一个函数和一个依赖关系列表(数组 [a,b])。它们的行为类似于函数中的参数。依赖关系列表是 useMemo 要去监视的元素:如果没有改变,那么函数的结果将会保持不变,否则它将重新运行这个函数。假如它们没有改变的话,那么重新渲染整个组件也没关系,该函数不会被重新执行,而是直接返回存储的结果。如果包装的函数很大且很运行代价高昂,那么这绝对是一个非常好的方案。这就是 useMemo 的主要用途。

useMemo 示例

代码语言:javascript
复制
const List = useMemo(
  () =>
  listOfItems.map(item => ({
    ...item,
    itemProp1: expensiveFunction(props.first),
    itemProp2: anotherPriceyFunction(props.second)
  })),
  [listOfItems]
)

在上面的例子中,useMemo 函数将在第一个渲染器上运行。它会阻塞线程,直到函数执行完毕,因为 useMemo 在渲染器中运行。它看起来不如 useEffect 干净,因为 useEffect 可以渲染加载微调器,直到运行代价高昂的函数完成并且效果消失为止。但是如果 listOfItems 从未被改变,那么函数将永远不会再次触发,仍然会获取返回值。这样会使这些函数的执行速度显得很快。这是你在执行高耗时的同步函数时的理想选择。

防止重新渲染

如果你熟悉 React 的类组件生命周期 Hook shouldComponentUpdateuseMemo 在防止不必要的重新渲染方面也有类似用法。假设有以下代码:

代码语言:javascript
复制
function BabyGator({fish, insects}) {
  const dinner = {fish, insects};
  useEffect(() => {
    eatFunction(dinner);
  }, [fish, insects])
}

function MamaGator() {
  return <BabyGator fish='small edible fish' insects={15}>
}

它工作得很好。useEffect hook 监视传入的 fishinsects。但是这仅适用于 primitive 值。这是关键。

还记得前面提到的“引用比较”吗: [] === [] // false。这正是 useMemouseCallback 之类的记忆 hook 所做的事。如果的 insects 是一个数组,我们可以把它放在 useMemo hook 中,在渲染之后,它将相等地引用它。如果一个函数或另一个非原始值位于 useEffect 依赖项中,由于closure 的原因,它将会重新创建一个新数组,并且发现它不相等。

很显然,如果我们只是想存储数组就不需要 useMemo。但是如果有一个代价高昂的函数来计算这个数组,useMemo是很有用的。

什么时候不能用 useMemo

useCallback 类似于 useMemo,但是它返回一个被记忆的函数,而 useMemo 有一个返回 value 的函数。如果依赖项数组为空,则不可能进行记忆,它将在每个渲染器上去计算新的值。在这时你最好实现 useRef 钩子。如果依赖项发生更改,则 useMemouseRef 优秀的一点是能够重新进行存储。

在实现 useMemo 时,你需要问问自己:“这真的是一个代价高昂的函数吗?” 代价高昂意味着它正在消耗大量资源(如内存)。如果在渲染时在函数中定义大量变量,则用 useMemo 进行记忆是非常有意义的。

如果你不希望 useMemo 去触发有副作用的操作或是异步调用。使用 useEffect 中会更有意义。

当你想要使用 useMemo 时,请先编写代码,然后再检查是否可以对其进行优化。不要一开始就去使用 useMemo 开头。这样可能会在小型应用中导致性能变差。

让你的 React 快速进阶的福利

成功的路上并不拥挤,因为嘴上说努力的人很多,真正去做的人少之又少。

就像你可能经常会领取到【海量前端资料包】,收藏起来就再也没看过。

在这样一个信息爆炸、知识唾手可得的时代,我们一定要做个明白人,懂得筛选和判断优质内容。

所以今天,我们想给你点真正有品质的内容 —— React 高级玩家必会指南

本次React专题课深度讲解 React 项目的性能优化、React Hooks 实践指南、React 大厂面试真题等 React 进阶必备指南

除以上课程内容外,还将有每日打卡抽奖惊喜、微信群答疑等课程服务,真正带你克服惰性,实现 React 进阶 !

它将带你学到什么?

1.React 项目的性能优化实践

大厂面试问React项目优化时的各种讲解,性能指标的各种优化逻辑

核心工程化知识点讲解

不同的核心优化方案剖析,首屏渲染、预加载、ssr等内部逻辑

常考React知识点串讲

2.React Hooks 实践指南

Hooks原理剖析

Hooks产生原因

项目结合Hooks的优化实践

大厂Hooks相关面试题

3. React 相关面试题精讲

深入内部串讲React各个相关面试题

React render渲染逻辑

createElement如何实现虚拟dom

内部核心原理串讲

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端桃园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档