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 组件就不会跟着渲染啦

posted @ 2022-04-18 16:46  Tommy_marc  阅读(861)  评论(0编辑  收藏  举报