【问题标题】:Why use useMemo and not useCallback here?为什么在这里使用 useMemo 而不是 useCallback?
【发布时间】:2022-01-21 03:02:54
【问题描述】:

所以据我了解,两者之间的区别在于,如果返回函数、对象或数组,则使用 useCallback,而返回原语时使用 useMemo。 但我正在寻找去抖动(这是文章:https://dmitripavlutin.com/react-throttle-debounce/,它说 useMemo 将是一个更好的解决方案。 使用 useCallback

import { useState, useCallback } from 'react';
import debounce from 'lodash.debounce';
export function FilterList({ names }) {
  const [query, setQuery] = useState("");
  let filteredNames = names;
  if (query !== "") {
    filteredNames = names.filter((name) => {
      return name.toLowerCase().includes(query.toLowerCase());
    });
  }
  const changeHandler = event => {
    setQuery(event.target.value);
  };
  const debouncedChangeHandler = useCallback(
    debounce(changeHandler, 300)
  , []);
  return (
    <div>
      <input 
        onChange={debouncedChangeHandler} 
        type="text" 
        placeholder="Type a query..."
      />
      {filteredNames.map(name => <div key={name}>{name}</div>)}
    </div>
  );
}

使用 useMemo

import { useState, useMemo } from 'react';
import debounce from 'lodash.debounce';
export function FilterList({ names }) {
  const [query, setQuery] = useState("");
  let filteredNames = names;
  if (query !== "") {
    filteredNames = names.filter((name) => {
      return name.toLowerCase().includes(query.toLowerCase());
    });
  }
  const changeHandler = (event) => {
    setQuery(event.target.value);
  };
  const debouncedChangeHandler = useMemo(
    () => debounce(changeHandler, 300)
  , []);
  return (
    <div>
      <input
        onChange={debouncedChangeHandler}
        type="text"
        placeholder="Type a query..."
      />
      {filteredNames.map(name => <div key={name}>{name}</div>)}
    </div>
  );
}

我不明白。 debounce 是否返回原始值?如果不是,我们如何使用 useMemo?还有在这里 useMemo 比 useCallback 更好吗?

【问题讨论】:

  • useCallback 接受一个函数,并返回那个被记忆的函数。 useMemo 接受一个返回值的函数,运行该函数,并记住该返回值。

标签: javascript reactjs react-hooks usecallback react-usememo


【解决方案1】:

首先关于您的报价:

如果函数、对象或数组被返回,则使用useCallback 返回原语时使用Memo

不,这是错误的。 useCallback 主要用于记忆功能。 useMemo 有助于避免昂贵的计算。


现在是文章。那篇文章更喜欢useMemo 的原因不同,那就是性能;尽管我怀疑在大多数此类情况下性能差异会很明显。

 const debouncedChangeHandler = useCallback(
    debounce(changeHandler, 300)
  , []);

上面写着:

但是...这个实现有一个小的性能问题:每个 组件重新渲染的时间,去抖动的新实例 函数由 debounce(changeHandler, 300) 创建。

意思是即使debouncedChangeHandler 在重新渲染时由于useCallback 保持不变,debounce(changeHandler, 300) 仍会在每次渲染时执行。

但是useMemo:

  const debouncedChangeHandler = useMemo(
    () => debounce(changeHandler, 300)
  , []);

它声称:

useMemo(() => debounce(changeHandler, 300), []) memoizes debounced 处理程序,而且仅在初始渲染期间调用 debounce() 组件。

因为useMemo 不像useCallback 不直接调用debounce,而是在一个内联函数中调用它。


运行此代码:

let T1 = () => console.log('test1');
let T2 = () => console.log('test2');

export default function App() {
  let f = React.useCallback(T1(), []);
  let g = React.useMemo(() => T2(), []);
  let [x, setX] = React.useState(0);
  return (
    <div
      onClick={() => {
        setX(x + 1);
      }}
    >
      <h1>{x}</h1>
      <p>Start editing to see some magic happen :)</p>
    </div>
  );
}

在任意位置单击div,看看test2 是如何不再被记录的。

【讨论】:

  • 谢谢,但我更困惑。我参加了一门课程,他们说这是 useMemo 和 useCallback 之间的区别。你能告诉我什么时候应该使用 useMemo 和 useCallback 吗?
  • @H.b 检查文档:很难解释为评论我建议在网上查找信息,应该有很多。 reactjs.org/docs/hooks-reference.html#usecallback
  • @giorgimoniava,我们可以做类似useCallback( (e) =&gt; debounce((e) =&gt; changeHandler(e), 300) , []); 的事情,而不是在每次渲染时调用useCallback 内部的去抖动吗?
  • @Shan 与 useCallback( debounce(changeHandler, 300),[]) 相比将返回 不同的结果。它将返回一个函数,您还必须在每次渲染时调用该函数;而且我不确定您是否会从使用 debounce 中受益。
  • @giorgimoniava 好的,知道了。
【解决方案2】:
  const debouncedChangeHandler = useCallback(
    debounce(changeHandler, 300)
  , []);

在每次渲染中:

  1. debounce(changeHandler, 300) 将运行(它不是一个函数,它是一个被调用函数)并解析为一个值(这是一个回调)
  2. 然后 useCallback 将运行,检查依赖关系以确定它是否应该返回记忆值(回调)或新值,所以在你的情况下,它将返回记忆值
  const debouncedChangeHandler = useMemo(
    () => debounce(changeHandler, 300)
  , [])

在每次渲染中

  1. () =&gt; debounce(changeHandler, 300) 不会运行,是值(回调)
  2. 然后 useMemo 将运行,它将检查依赖关系以确定是否运行回调,在您的情况下,它不会运行回调

因此 useMemo 更高效

【讨论】:

    猜你喜欢
    • 2022-12-18
    • 1970-01-01
    • 2020-06-01
    • 1970-01-01
    • 2021-05-31
    • 1970-01-01
    • 2019-07-24
    • 2012-02-26
    相关资源
    最近更新 更多