小白篇--了解 useCallback 和 useMemo

2,841 阅读2分钟

前言

使用 hook 也有一段时间了,但是 useCallbackuseMemo 还不是傻傻分不清(虽某种程度上可以相互相当)和具体使用场景,遂整理一下。

useCallback

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

返回一个 memoized 回调函数。(缓存函数)

使用方式

没有使用 useCallback ,函数 fetchData 会一直被执行:

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

export default function App() {
  const [data, setData] = useState(null)
  const [manualRendering, setManualRendering] = useState(1)

  const handleChange = () => {
    setManualRendering(manualRendering + 1)
  }

  const fetchData = async () => {
    console.log('我是一个函数,我又被执行了。')
    const res = await fetch(`https://jsonplaceholder.typicode.com/users`)
    setData(res)
  }

useEffect(() => {
    fetchData()
  }, [fetchData]) // 总之是会执行多次,但是 fetchData 只需要执行一次

  return (
    <div className='App'>
      <h1>Hello Hooks</h1>
      <button onClick={handleChange}>Re-render</button>
    </div>
  )
}

使用了 useCallback ,函数 fetchData 就不会一直被执行,或者会按照依赖项数组再次执行:

// 需要引入 useCallback 或者直接使用 React.useCallback(但不建议) 

  // const fetchData = async () => {
  //   console.log('我是一个函数,我又被执行了。')
  //   const res = await fetch(`https://jsonplaceholder.typicode.com/users`)
  //   setData(res)
  // }

  const fetchData = useCallback(async () => {
    console.log('我是一个函数,我又被执行了。')
    const res = await fetch(`https://jsonplaceholder.typicode.com/users`)
    setData(res)
  }, []) // 依赖项数组可任意添加。

useMemo

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

返回一个 memoized 值。(缓存值)

使用方式

没有使用 useMemo ,复杂函数 computeExpensiveValue 会一直被执行:

import React, { useState } from 'react'
import "./styles.css";

export default function App() {
  const [manualRendering, setManualRendering] = useState(1)

  // 假设为很复杂的计算
  const computeExpensiveValue = () => {
    console.log('我是一个值,我又被计算了。')
    let newValue = 1
    for (let i = 1; i < 100; i++) {
      newValue = newValue * i
    }
    return newValue
  }

  const handleChange = () => {
    setManualRendering(manualRendering + 1)
  }

  const noMemoData = computeExpensiveValue()

  return (
    <div className='App'>
      <h1>Hello Hooks</h1>
      <h2>{noMemoData}</h2>
      <button onClick={handleChange}>Re-render</button>
    </div>
  )
}

频繁点击按钮 ,复杂函数 computeExpensiveValue 会一直执行:

使用了 useMemo ,复杂函数 computeExpensiveValue 就不会一直被执行,或者会按照依赖项数组再次执行:

// 需要引入 useMemo 或者直接使用 React.useMemo(但不建议) 

// const noMemoData = computeExpensiveValue()
const useMemoData = useMemo(() => computeExpensiveValue(), []) // 依赖项数组可任意添加。

总结

  • 某种程度上看,两者也是有很大的联系的,某种程度可以相互相当:

    useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

  • 以上只是简单理解 useCallbackuseMemo ,并不是所有情况都得加上 useCallbackuseMemo ,不合理的地方加上反倒增加性能消耗。