他们说90%的useMemo和useCallback可以删掉

useMemo: 缓存值,在每次重渲染之间缓存数据,避免组件重新渲染

useCallback: 缓存函数,在每次重渲染之间缓存数据,避免组件重新渲染

例如:

// bad
// 比较”重渲染之前的 a“ 和 ”重渲染之后的 a“,结果都会是 false,所以被 useEffect 包裹的函数也将会在每次重渲染的过程中触发调用
const Component = () => {  
  const a = { test: 1 };
  useEffect(() => {    
    // "a" 将会在每次重渲染时被比较
  }, [a]);
  // 你剩下的代码
};



// good
const Component = () => {
  // 在每次重渲染之间保存 a
  const a = useMemo(() => ({ test: 1 }), []);

  useEffect(() => {
    // 只有当 a 的值真实发生改变时才会触发
  }, [a]);
  // 你剩下的代码
};


const Component = () => {
  // 在每次重渲染之间保存 onClick 方法
  const fetch = useCallback(() => {
    console.log('fetch some data here');  
  }, []);
  useEffect(() => {    
    // 只有当 fetch 的值真的发生该表的时候才会触发
    fetch();  
  }, [fetch]);
  // 你剩下的代码
};

在这里,需要记住的最重要的一件事是,useMemo 和 useCallback 只有在重渲染的过程中才有用

当 state 或者 prop 发生变化的时候,组件就会重渲染自己,当一个组件重渲染它自己的时候,它也会同时重渲染它的 children

例如:

// 父组件
const App = () => {
  const [state, setState] = useState(1);
  return (
    <div className="App">
      <button onClick={() => setState(state + 1)}>
        click to re-render {state}
      </button>
      <br />
      <Page />
    </div>
  );
};




// 子组件
const Page = () => <Item />;

当App中的state改变的时候,会导致App重新渲染,并且会重渲染它所有的children,及时Page 组件甚至没有 props!也没有 state。

当我们使用React.memo缓存组件时


const PageMemoized = React.memo(Page);


const App = () => {
  const [state, setState] = useState(1);
  return (
    ... // same code as before
    <PageMemoized />
  );
};

可以解决重渲染问题。

让我们试想一下,如果给page传递一个事件呢?

const App = () => {
  const [state, setState] = useState(1);
  const onClick = () => {
    console.log('Do something on click');
  };
  return (
    // 不管 onClick 有没有缓存,page 都会重渲染
    <Page onClick={onClick} />
  );
};

App和Page都会重渲染,onClick有没有包裹useCallback并不重要

即使我们把Page缓存起来

const PageMemoized = React.memo(Page);
const App = () => {
  const [state, setState] = useState(1);
  const onClick = () => {
    console.log('Do something on click');
  };
  return (
    // 因为 onClick 没有缓存,PageMemoized 「将会」重渲染
    <PageMemoized onClick={onClick} />
  );
};

App 会重渲染,React 会在它的 children 中发现 PageMemoized 组件,并意识到它被 React.memo 方法包裹,这会打断重渲染链条,React 会事先检查这个组件的 props 是否有变化。在这个例子里,既然 onClick 是一个未被缓存的函数,props 比较的结果就会是 false,那么 PageMemoized 组件就会重渲染它自己。

const PageMemoized = React.memo(Page);
const App = () => {
  const [state, setState] = useState(1);
  const onClick = useCallback(
    () => { console.log('Do something on click');  }, 
    []
  );
  return (
    // PageMemoized 因为 onClick 被缓存了,将「不会」重渲染
    <PageMemoized onClick={onClick} />
  );
};

现在,当 React 检查 PageMemoized 的 props 有无变化时,onClick 将会保持不变,只有在这种情况下, PageMemoized 才不会重渲染

这个时候,如果我再给PageMemoized组件传递一个属性值呢?

const PageMemoized = React.memo(Page);
const App = () => {
  const [state, setState] = useState(1);
  const onClick = useCallback(
    () => { console.log('Do something on click'); },
    []
  );
  return (
    // 因为 value 没有被缓存,page 「将会」重渲染
    <PageMemoized onClick={onClick} value={[1, 2, 3]} />
  );
};

由于value没有缓存,所以PageMemoized还是会重新渲染

所以可以得出结论:只有在唯一的一种场景下,缓存 props 才是有意义的---当组件的每一个 prop,以及组件本身被缓存的时候

如果组件代码里有以下情形,我们可以毫无心理负担地删掉 useMemouseCallback

  • 它们被作为 attributes ,直接地或作为依赖树的上层,被传递到某个 DOM 上
  • 它们被作为 props,直接地或作为依赖树的上层,被传递到某个未被缓存的组件上
  • 它们被作为 props,直接地或作为依赖树的上层,被传递到某个组件上,而那个组件至少有一个 prop 未被缓存

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值