React Hooks系列之useCallback


useCallback介紹

useCallback 可以說是 useMemo 的語法糖,能用 useCallback 實現,都可以用 useMemo,常用語 react 的性能優化。 在 react 中我們經常面臨一個子組件渲染優化的問題,尤其是在向子組件傳遞函數 props 時,每次 render 都會創建新函數,導致子組件不必要的渲染,浪費性能,這個時候,就是useCallback 的用武之地,useCallback 可以保證,無論 render 多少次,我們的函數都是同一個函數,減少了不斷創建的開銷。

const memoCallback = useCallback(callback, array)

返回一個memoized 回調函數。

  • callback 是一個函數用於處理邏輯
  • array 控制 useCallback 重新執行的數組,array 改變時才會重新執行useCallback
  1. 數組,每次更新都會重新計算
  2. 空數組,只會計算一次
  3. 依賴對應的值,對應的值發生變化重新計算
  • useCallback(fn, deps) 相當於 useMemo(() => fn, deps)

useCallback 使用

function App () {
  const [ count, setCount ] = useState(0)
  const add = useCallback(() => count + 1, [count])
  return (
    <div>
      點擊次數: { count }
      <br/>
      次數加一: { add() }
      <button onClick={() => { setCount(count + 1)}}>點我</button>
    </div>
    )
}

應用場景:

import React, { useState } from 'react'
class Test extends React.PureComponent {
  render() {
    console.log("Test Render")
    return <div>
      <h1>{this.props.text}</h1>
      <button onClick={this.props.onClick}>改變文本</button>
    </div>
  }
}
const Parent = () => {
  console.log("Parent Render")
  const [txt, setTxt] = useState(123)
  const [n, setN] = useState(0)
  return (
    <div>
      <Test text={txt} onClick={() => {
        setTxt(123)
      }}></Test>
      <input type="number"
        value={n}
        onChange={
          e => {
            setN(parseInt(e.target.value))
          }
        }></input>
    </div>
  )
}
const App = () => {
  return (
    <div>
      <Parent />
    </div>
  )
}
export default App

理論來說,Test 作為純組件,只有在傳入發生改變的時候才會重新渲染,當點擊改變文本的按鈕時,setTxt所更改的值與本身Txt的值相同,所以Test 組件不會重新渲染,不會打印test Render

問題所在就是,當Parent 組件中的其他值發生改變的時候,Parent 組件便會重新渲染,而Test 組件中Txt 的值雖然沒有改變, 但傳入的() => { setTxt(123) } 作為方法對象,會創建一個新的地址棧, 兩次地址的指向不同了,所以會認為傳入的值發生了改變,所以 Test 組件發生了重新渲染

image

這樣的渲染浪費了不必要的性能,所以 useCallback 就是用來解決這一問題的

import React, { useState,useCallback } from 'react'
class Test extends React.PureComponent {
  render() {
    console.log("Test Render")
    return <div>
      <h1>{this.props.text}</h1>
      <button onClick={this.props.onClick}>改變文本</button>
    </div>
  }
}
const Parent = () => {
  console.log("Parent Render")
  const [txt, setTxt] = useState(123)
  const [n, setN] = useState(0)
  const hhh = useCallback(()=> {
    setTxt(223)
  },[])
  return (
    <div>
      <Test text={txt} onClick={hhh}></Test>
      <input type="number"
        value={n}
        onChange={
          e => {
            setN(parseInt(e.target.value))
          }
        }></input>
    </div>
  )
}
const App = () => {
  return (
    <div>
      <Parent />
    </div>
  )
}
export default App

image

這樣當改變n的值時 Test 組件就不會跟着渲染啦


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM