React hooks useCallback 指北

react useCallback 指北

基本使用

useCallback(callback: T, deps: DependencyList): callbackjavascript

把內聯回調函數及依賴項數組做爲參數傳入 useCallback,它將返回該回調函數的 memoized 版本,該回調函數僅在某個依賴項改變時纔會更新。當你把回調函數傳遞給通過優化的並使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子組件時,它將很是有用。java

問題

useCallback 返回的函數裏面緩存了什麼數據react

import React, { useCallback, useState } from 'react';

class Child extends React.Component {
  shouldComponentUpdate(nextProps) {
    return nextProps.flag !== this.props.flag;
  }

  render() {
    console.log('Child render');
    return <div>Child Count: {this.props.count}</div>;
  }
}

const UseCallBack = () => {
  const [count, setCount] = useState(0);
  const [selfCount, setSelfCount] = useState(100);

  const memoizedCallback = useCallback(() => {
    console.log('count change', count, selfCount);
  }, [count]);

  return (
    <div> <Child count={count} flag={memoizedCallback} /> <p>self Count:{selfCount}</p> <p onClick={() => setCount(count + 1)}>child count add</p> <p onClick={() => setSelfCount(selfCount + 1)}>self count add</p> <p onClick={() => memoizedCallback()}>callback click</p> </div> 複製代碼

能夠看到,當咱們改變 selfCount 的時候,因爲咱們的deps裏面只監聽了 count,因此返回的 memoizedCallback 是沒有變化的,Child 沒有 re-render,當memoizedCallback執行的時候打印的selfCount 仍是以前的狀態,沒有發生變化。數組

結論

useCallback執行返回的函數,是第一個傳入的第一個函數的 memoized 版本,而且會緩存 useState 的全部值,只有在 deps 發生變化,返回值才函數纔會更新,其內部的 useState的 值纔會更新 。緩存

使用場景

function Counter() {
  const [count, setCount] = useState(0);
  const handleIncr = () => {
    setCount(c + 1);
  };

  return (
    <div> {count} <Child onClick={handleIncr} /> </div> ); } 複製代碼

假設Child是一個很是複雜的組件,每一次點擊它,咱們會遞增count,從而觸發組將從新渲染。由於Counter每次渲染都會從新生成handleIncr,因此也會致使Child從新渲染,無論Child使用了PureComponent仍是使用React.memo包裝。bash

在這裏我使用useCallback去緩存咱們的 handleIncr閉包

function Counter() {
  const [count, setCount] = useState(0);
  const handleIncr = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return (
    <div> {count} <Child onClick={handleIncr} /> </div> ); } 複製代碼

只有在count發生變化的時候纔會從新生成 handleIncr,這樣雖然能避免了一些性能問題,可是若是須要監聽的變量過多,好比 useCallback(fn, [a, b,c, d]) 這樣就會讓代碼變的很亂。 其實在這裏咱們只要改變一下思路,在setCount 這樣操做的時候,不用閉包中的變量,而是使用函數,獲取最新的值。函數

const Child = React.memo(({ onClick }) => {
  console.log('child render');
  return <div onClick={onClick}>click</div>;
});

function Counter() {
  const [count, setCount] = useState(0);
  const handleIncr = useCallback(() => {
    setCount(c => c + 1);
  }, []);

  return (
    <div>
      {count} <Child onClick={handleIncr} />
    </div>
  );
}
複製代碼

這樣 handleIncr 在每次 Counter re-render 的時候都不會改變,而且每次操做的也是最新值性能

相關文章
相關標籤/搜索