React Hooks 系列之6 useMemo

本系列将讲述 React Hooks 的使用方法,从 useState 开始,将包含以下内容:css

  • useState
  • useEffect
  • useContext
  • useReducer
  • useCallback
  • useMemo
  • useRef
  • custom hooks

掌握 React Hooks api 将更好的帮助你在工做中使用,对 React 的掌握更上一层楼。本系列将使用大量实例代码和效果展现,很是易于初学者和复习使用。react

上一章,咱们学习了 useCallback 来进行性能优化,关于性能优化还有另外一个 hook api,那就是 useMemo,下面咱们一块儿经过一个例子来看看。api

计数器示例

依然是计数器示例,建立2个计数器,并能区分当前是奇数或者偶数,为了模拟点击按钮时包含大量的计算逻辑影响性能,在判断偶数的方法中添加了没有用的计算逻辑,为了让性能差的明显。代码以下数组

Counter.tsx缓存

import React, { useState } from 'react'

function Counter() {
  const [counterOne, setCounterOne] = useState(0)
  const [counterTwo, setCounterTwo] = useState(0)

  const incrementOne = () => {
    setCounterOne(counterOne + 1)
  }

  const incrementTwo = () => {
    setCounterTwo(counterTwo + 1)
  }

  const isEven = () => {
    let i = 0
    while (i < 1000000000) i += 1
    return counterOne % 2 === 0
  }

  return (
    <div> <button onClick={incrementOne} >Count One = {counterOne}</button> <span> { isEven() ? 'even' : 'odd' } </span> <br /> <button onClick={incrementTwo} >Count Two = {counterTwo}</button> </div>
  )
}

export default Counter
复制代码

App.tsx性能优化

import React from 'react'
import './App.css'

import Counter from './components/27.Counter'

const App = () => {
  return (
    <div className="App"> <Counter /> </div>
  )
}

export default App
复制代码

页面展现以下函数

咱们发现点击第一个按钮有较长的延迟,由于咱们的判断偶数的逻辑中包含了大量的计算逻辑。可是,咱们点击第二个按钮,也有较长的延迟!这很奇怪。性能

这是由于,每次 state 更新时,组件会 rerender,isEven 会被执行,这就是咱们点击第二个按钮时,也会卡的缘由。咱们须要优化,告诉 React 不要有没必要要的计算,特别是这种计算量复杂的。学习

在咱们的示例中,咱们要告诉 React,在点击第二个按钮时,不要执行 isEven 方法。这时就须要 useMemo hook 登场了。优化

useMemo

优化示例

与 useCallback 的用法相似。

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

返回一个 memoized 值。 把“建立”函数和依赖项数组做为参数传入 useMemo,它仅会在某个依赖项改变时才从新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

记住,传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操做,诸如反作用这类的操做属于 useEffect 的适用范畴,而不是 useMemo

若是没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。

你能够把 useMemo 做为性能优化的手段,但不要把它当成语义上的保证。 未来,React 可能会选择“遗忘”之前的一些 memoized 值,并在下次渲染时从新计算它们,好比为离屏组件释放内存。先编写在没有 useMemo 的状况下也能够执行的代码 —— 以后再在你的代码中添加 useMemo,以达到优化性能的目的。

首先引入 useMemo

import React, { useState, useMemo } from 'react'
复制代码

而后将 isEven 方法使用 useMemo 改写,返回值赋给 isEven

const isEven = useMemo(() => {
  let i = 0
  while (i < 1000000000) i += 1
  return counterOne % 2 === 0
}, [counterOne])
复制代码

最后记得修改 isEven 使用的地方,已经从一个方法变为了一个变量

{
  isEven ? 'even' : 'odd'
}
复制代码

完整代码以下

Counter.tsx

import React, { useState, useMemo } from 'react'

function Counter() {
  const [counterOne, setCounterOne] = useState(0)
  const [counterTwo, setCounterTwo] = useState(0)

  const incrementOne = () => {
    setCounterOne(counterOne + 1)
  }

  const incrementTwo = () => {
    setCounterTwo(counterTwo + 1)
  }

  const isEven = useMemo(() => {
    let i = 0
    while (i < 1000000000) i += 1
    return counterOne % 2 === 0
  }, [counterOne])

  return (
    <div> <button onClick={incrementOne} >Count One = {counterOne}</button> <span> { isEven ? 'even' : 'odd' } </span> <br /> <button onClick={incrementTwo} >Count Two = {counterTwo}</button> </div>
  )
}

export default Counter
复制代码

效果以下

咱们看到点击第二个按钮时,不会有任何卡顿,这是由于使用了 useMemo 只依赖了 counterOne 变量,点击第二个按钮时,isEven 读取的是缓存值,不须要再从新计算是否为偶数。

useMemo 与 useCallback 的区别

useCallback 是缓存了函数自身,而 useMemo 是缓存了函数的返回值。

小结

本章经过示例展现了 useMemo 在性能优化中的做用。经过缓存函数的返回值,避免没必要要的调用,从而避免了组件 rerender。

最后有分析了 useMemo 与 useCallback 的区别,即 useMemo 是缓存了函数的返回值,useCallback 是缓存了函数自身。这两个 api 都是性能优化的方法。

相关文章
相关标签/搜索