2

因此,据我了解,两者之间的区别在于,如果返回函数、对象或数组,则使用 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>
  );
}

带使用备忘录

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 更好吗?

4

2 回答 2

4

首先关于你的报价:

如果返回一个函数或对象或数组,则使用 useCallback,而当返回一个基元时使用 useMemo

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


现在来看这篇文章。那篇文章更喜欢useMemo性能的另一个原因。尽管我怀疑在大多数此类情况下性能差异会很明显。

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

它说:

但是......这个实现有一个小的性能问题:每次组件重新渲染时,debounce(changeHandler, 300) 都会创建一个 debounced 函数的新实例

这就是说,即使debouncedChangeHandler由于 ,在重新渲染中保持不变useCallbackdebounce(changeHandler, 300)仍然在每次渲染时执行。

但随着useMemo

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

它声称:

useMemo(() => debounce(changeHandler, 300), []) 记忆去抖处理程序,但也仅在组件的初始渲染期间调用 debounce()

因为useMemolike 不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不再记录。

于 2022-01-20T16:49:27.560 回答
1
  const debouncedChangeHandler = useCallback(
    debounce(changeHandler, 300)
  , []);

在每个渲染中:

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

在每次渲染中

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

因此 useMemo 更有效

于 2022-01-20T17:02:49.460 回答