blog icon indicating copy to clipboard operation
blog copied to clipboard

useCallback使用场景

Open xianzou opened this issue 4 years ago • 0 comments

useCallback使用场景

1、作为props,传递给子组件,为避免子元素不必要的渲染,需要配合React.Memo或者useMemo使用,否则无意义:

useMeno使用

import React,{useEffect,useState,useCallback,useMemo} from "react";
//子元素
const Child = () => {
  const [count, setCount] = useState(() => callback());
  alert('更新了');
  useEffect(() => {
      setCount(callback());
  }, [callback]);
  return <div>
      {count}
  </div>
}

//父元素
export default function App() {
  const [count, setCount] = useState(1);
  const [val, setVal] = useState('');

  const callback = useCallback(() => {
      return count;
  }, [count]);

  const Children = useMemo(() => <Child callback={callback}/>,[callback]);

  return <div>
      <h4>{count}</h4>
      {
        Children
      }
      <div>
          <button onClick={() => setCount(count + 1)}>+</button>
          <input value={val} onChange={event => setVal(event.target.value)}/>
      </div>
  </div>;
}

React.memo使用:

// 子元素
const Child = React.memo(({ callback }) => {
  const [count, setCount] = useState(() => callback());
  alert('更新了');
  useEffect(() => {
      setCount(callback());
  }, [callback]);
  return <div>
      {count}
  </div>
})
//父元素
export default function App() {
  const [count, setCount] = useState(1);
  const [val, setVal] = useState('');

  const callback = useCallback(() => {
      return count;
  }, [count]);

  return <div>
      <h4>{count}</h4>
      <Child callback={callback}/>
      <div>
          <button onClick={() => setCount(count + 1)}>+</button>
          <input value={val} onChange={event => setVal(event.target.value)}/>
      </div>
  </div>;
}

当我们再输入框输入的时候 子元素不会重新渲染;

2、作为useEffect的依赖项,需要进行比较的时候才需要加上useCallback;

//子元素
function Foo({bar}) {
  React.useEffect(() => {
    const options = bar
  }, [bar])
  return <div>foobar</div>
}
// 父级
function Blub() {
  //源代码 const bar = {};
  // 优化后的代码,使用useCallback包裹
  const bar = React.useCallback(() => {}, [])
  return <Foo bar={bar} />
}


总结:

记住useCallbackuseMemo这两个内置的API,都有特别的原因:

  • 引用相等
  • 昂贵的计算

什么是引用相等:

true === true // true
false === false // true
1 === 1 // true
'a' === 'a' // true

{} === {} // false
[] === [] // false
() => {} === () => {} // false

const z = {}
z === z // true
// NOTE: React 使用的是 Object.is, 和 === 非常类似

在React函数组件中定义一个对象时,它跟上次定义的相同对象,引用是不一样的(即使它具有所有相同值和相同属性);

那么,再React中有两种引用相等很重要:

  • React.memo;(也就是场景一)
  • 依赖列表(场景二)

所以如下场景其实没有必要加上:

//这里的方法没有必要加上useCallback
const submit = () => {
    //提交动作
};
<button onClick={submit}>点击提交</button>

所以有如下结论:只有当该方法会被拿去做引用对比的时候,才需要写useCallback,否则性能反而不会提升,普通的方法可以不必要加

参考材料

xianzou avatar Apr 08 '20 06:04 xianzou