useMemo 或 useCallback的使用场景

建議使用 useCallback 的時機

如果你的 function 因為需要用到 props 或 state 而必須在 component scope 裡面宣告、但又同時會被超過一個 useEffect 使用時,就建議以 useCallback 包起來。

這樣可以確保當 props 或 state 改變時,useCallback 先跟著改變、進而觸發 useEffect 的行為。

// When your callback are used in multiple useEffect() 
function SearchResults({ query }) {
    const getFetchUrl = useCallback(() => {
    return 'https://hn.algolia.com/api/v1/search?query=' + query;
    }, [query]);
useEffect(() => {
    const url = getFetchUrl('react');
    // ... Fetch data and do something ...
    }, [getFetchUrl]);
useEffect(() => {
    const url = getFetchUrl('redux');
    // ... Fetch data and do something ...
    }, [getFetchUrl]);
// ...
}

如果你傳給 useMemo 的 function 裡面運算很繁重,例如可能要 map 一組很大的陣列,這時候可能就很值得用 useMemo 把運算結果暫記起來下次用。

// Assume this returns an Array of 3000 records
const menuItemRows = useMemo(
    () => thousandsOfMenuItems.map(menuItem => (
        <MenuItemRow key={menuItem.uuid} name={menuItem.name} />
    )),
    [thousandsOfMenuItems]
);

const [count, setCount] = useState(1);
const consoleFunction = useCallback(() => {
    console.log('consoleFunction');
}, []);
useEffect(() => {
    setCount(count + 1);
    console.log(`第二个参数: 函数, 第 ${count} 次执行`);
}, [consoleFunction]);
// 打印log,执行一次
第二个参数: 函数, 第 1 次执行

const [count, setCount] = useState(1);
const obj = useMemo(() => ({name: 'zhangsan'}), []);
useEffect(() => {
    setCount(count + 1);
    console.log(`第二个参数: 对象, 第 ${count} 次执行`);
}, [obj]);
// 打印log
第二个参数: 对象, 第 1 次执行

如果 react + ts, useCallback 必须传入第二个参数,useMemo 可选填

如果传入的第二个参数是一个 空数组,后续的渲染,只会记住第一次渲染的

If no array is provided, a new value will be computed on every render.

如果 useMemo 不传入参数,相当于没有 使用 useMemo, 每次都会重新 computed

参考链接
使用 React.memo 和 React.useMemo 对项目性能优化 - 掘金

误区一:

import { useCallback, useState } from "react";

const Child = (props) => {};
const App = () => {
  const handleChange = useCallback(() => {}, []);
  const [count, setCount] = useState(0);
  return (
    <>
      <div
        onPress={() => {
          setCount(count + 1);
        }}
      >
        increase
      </div>
      <Child handleChange={handleChange} />
    </>
  );
};

export default App;

误区二:

import { useCallback, useState, memo } from "react";

const Child = memo((props) => {});
const App = () => {
  const handleChange = () => {};
  const [count, setCount] = useState(0);
  return (
    <>
      <div
        onPress={() => {
          setCount(count + 1);
        }}
      >
        increase
      </div>
      <Child handleChange={handleChange} />
    </>
  );
};

export default App;

对于复杂的组件项目中会使用 memo 进行包裹,目的是为了对组件接受的 props 属性进行浅比较来判断组件要不要进行重新渲染。这当然是正确的做法,但是问题出在 props 属性里面有引用类型的情况,例如数组、函数,如果像上面这个例子中这样书写,handleChange 在 App 组件每次重新渲染的时候都会重新创建生成,引用当然也是不一样的,那么势必会造成 Child 组件重新渲染。所以这种写法也是白给的。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值