React Hooks 指北(六):useMemo

613 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

1.介绍

useMemo和useCallback都是用于优化的手段,其中useCallback是用于父组件给儿子组件传递函数时的优化。 而useMemo是用于对复杂计算的缓存优化,学过vue的应该知道computed计算属性,useMemo和其功能大体一致。

2.使用

  • 第一个参数是一个回调函数,回调函数内部可以执行复杂计算场景

  • 第二个参数是一个依赖数组,

      useMemo(()=>{
          调用复杂计算
      },[[])
    

3.应用

未使用useMemo

Home.js

import { useState} from "react"
export default function Home() {
  let [num, setNum] = useState(1)
  let [name,setName] = useState("xiaoming")
  
  //模拟复杂计算
  function sum(n) {
    console.log("计算了")
    let total = 0
    for (let i = 0; i < n; i++) total += i
    return total
  } 
  return <div>
    <div onClick={() => setNum(num + 1)}>点击修改num:{num}</div>
    <div>{sum(num)}</div>
    <div onClick={() => setName(name+"1")}>点击修改name:{name}</div>

  </div>
}

3.gif

我们可以发现,当修改num和name时,复杂计算函数sum都会被重新调用。这是符合预期的,但是我们期望复杂计算应该在num改变时在重新计算,其它情况没必要重新计算。那么useMemo就可以做到

使用useMemo

import { useState, useMemo } from "react"
export default function Home() {
  let [num, setNum] = useState(1)
  let [name,setName] = useState("xiaoming")
  
  function sum(n) {
    console.log("计算了")
    let total = 0
    for (let i = 0; i < n; i++) total += i
    return total
  } 
  //对sum函数缓存,num改变了,才重新调用sum函数
  const total = useMemo(() => {
    return sum(num)
  },[num])

  return <div>
    <div onClick={() => setNum(num + 1)}>点击修改num:{num}</div>
    <div>{total}</div>
    <div onClick={() => setName(name+"1")}>点击修改name:{name}</div>

  </div>
}


4.gif

对比发现,当我们点击num修改时,因为依赖项改变了,所以sum函数不断被调用。而点击name修改时,依赖项没有改变,所以函数不会被调用,其结果已经做到了缓存。

注意点

useMemo和useCallback的第二个参数都是一个依赖数组,我们应该正确的填充和第一个回调函数相关的依赖项,否则会出现意想不到的逻辑错误。

栗子

import { useState, useMemo } from "react"

export default function Home() {
  let [num, setNum] = useState(1)
  let [name,setName] = useState("xiaoming")
  
  function sum(n) {
    console.log("计算了")
    let total = 0
    for (let i = 0; i < n; i++) total += i
    return total
  } 
  //缓存效果,num改变了,才重新计算
  const total = useMemo(() => {
    return sum(num)
  },[name])

  return <div>
    <div onClick={() => setNum(num + 1)}>点击修改num:{num}</div>
    <div>{total}</div>
    <div onClick={() => setName(name+"1")}>点击修改name:{name}</div>

  </div>
}

5.gif

函数sum的计算是根据num完成的。而我们在依赖项数组写了name.也就是只有name改变了,我们才会执行这个sum函数。因此会出现修改num,而计算的sum值未更新,当修改name时,计算的num数字更新。

总结

  1. useMemo用于缓存复杂计算
  2. useMemo无论是否使用,首次加载就会执行一次。
  3. useMemo只有首次加载和依赖发生更新时才会重新执行,其它情况都不会执行。