Re: 新手让网页 act 起来: Day22 - React Hooks 之 useCallback

前言

useCallback 常常会被用来优化效能,减少 React 不必要的 render ,但如果没有好好理解它,滥用 useCallback 的话反而会导致效能更差。今天就让我们来了解一下 useCallback 的基本用法,跟使用时机吧!

useCallback

如果之前对 useEffect 够熟悉的话,useCallback 应该会蛮快上手的。它跟 useEffect 一样接受两个参数:

  1. callback
  2. dependency array

然後回传一个 memoized callback ,而这个 callback 就是第一个参数传进去的 callback

const memorizeCallback = useCallback(() => {
  // do something
}, [])

那什麽是 memoized callback 呢? 你可以想像 useCallback 将你传进去的 function 纪录起来,并且再吐还给你,当下次元件 re-render 的时候,会根据你的 dependency array 来决定要不要生成一个新的 function ,还是将上次纪录下来的吐出来。

所以正常来说,如果没有使用 useCallback 的话,在元件中定义的 function ,当每次 re-render 都会生成一个新的。

如果还没有画面,可以看看下面的范例:

  function App() {
    const [count, setCount] = React.useState(0)
    const callbackRef = React.useRef()

    const test = () => {
      console.log('test callback')
    }

    React.useEffect(() => {
      callbackRef.current = test
    }, [])

    React.useEffect(() => {
      console.log(test === callbackRef.current)
    }, [count])

    return (
      <div>
        <button onClick={() => setCount(count + 1)}>{count}</button>
      </div>
    )
  }

  ReactDOM.render(<App />, document.getElementById('root'));)

打开 console 就会发现第一次会是 true ,而当 count 变化 re-render 後,test 的 function 就跟一开始的不一样了,所以都得到 false。

使用 useCallback :

  const test = React.useCallback(() => {
    console.log('test callback')
  }, [])

如此一来,当之後 re-render test 都会是最一开始的的实体。

那什麽时候需要 useCallback 来帮助我们纪录 function 呢?接下来就让我们来看看范例吧!

范例

当我们在使用打 api 的时候往往建议将 function 定义在 useEffect 当中:

React.useEffect(()=> {
  function fetchData(query){
    const baseUrl = `xxxxxxxx?${query}`
  }

fetchData('JavaScript')

}, [])

但假设我们其他方也需要用到这个 fetchData 时,我们就必须将它定义在外面

function fetchData(query){
  const baseUrl = `xxxxxxxx?${query}`
}

React.useEffect(()=> {
  fetchData('JavaScript')
}, [])

React.useEffect(()=> {
  fetchData('React')
}, [])

这个时候如果按照 eslint 的提醒,我们就必须把 fetchData 放到 dependency array 中,但这样做如果别的 state 改变了,会导致 re-render 然後 fetchData 又会是新的实体,就会造成 useEffect 执行。所以这个时候,其中一种的解决方案就是使用 useCallback 。

const fetchData = React.useCallback((query) => {
  const baseUrl = `xxxxxxxx?${query}`
}, [])

React.useEffect(()=> {
  fetchData('JavaScript')
}, [fetchData])

React.useEffect(()=> {
  fetchData('React')
}, [fetchData])

这样子 fetchData 就能够很安全的放到 useEffect 的 dependency array 中了!

再来如果说 query 是从 state 来的话,我们就需在 useCallback 的 dependency array 放上 query

const [query, setQuery] = React.useState('JavaScript')

const fetchData = React.useCallback((query) => {
  const baseUrl = `xxxxxxxx?${query}`
}, [query])

React.useEffect(()=> {
  fetchData()
}, [fetchData])

以上就是第一种 useCallback 的使用情境,当我们需要将 function 放入 useEffect 的 dependency array 时,要先思考一下,这样子是不是想要达到的效果,还是需要用到 useCallback 将它纪录起来。明天我们将再继续聊聊,什麽样的情况下适合用 useCallback 来减少 render 次数,以及什麽时候是不必要用的情况!

今天的介绍就到这边,有什麽问题都欢迎在下方留言告诉我!

该文章同步发布於:我的部落格


<<:  自动化 End-End 测试 Nightwatch.js 与 BrowserStack

>>:  30-22 之 Remote Facade

英雄列表范例:修改英雄

为了让使用者更直觉的修改,我希望能直接点英雄的名字就切换成可修改的输入元件,修改完後就直接存回後端。...

[DAY03] 建立 Datastore 和 Dataset (上)

DAY03 建立 Datastore 和 Dataset (上) 我们都知道做 AI 最重要的就是 ...

D3 - 今天点个 String Methods 套餐

前言 今天来讲讲 String Methods,你知道其实除了length 以外,String 还内...

[Day10] [笔记]React Hooks-useMemo、useCallback

前言 我们昨天介绍了 Hooks 中比较常用的 UseState 跟 UseEffect,那我们今天...

国家标准技术研究院(NIST)最低安全要求的最佳来源-标准

NIST出版物 NIST制定并维护了大量有关信息和信息系统的安全性和隐私性的标准,指南,建议和研究。...