为什么这里使用 useMemo 而不是 useCallback ?

H.b*_*H.b 5 javascript reactjs react-hooks usecallback react-usememo

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

与 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>
  );
}
Run Code Online (Sandbox Code Playgroud)

我不明白。debounce 是否返回原始值?如果没有我们如何使用useMemo?另外,useMemo 比 useCallback 哪里更好?

gio*_*gim 9

首先关于你的报价:

如果返回函数、对象或数组,则使用 useCallback;如果返回原语,则使用 useMemo

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


现在来说说文章。那篇文章useMemo出于不同的原因而倾向于,即性能。尽管我怀疑在大多数此类情况下性能差异是否会很明显。

 const debouncedChangeHandler = useCallback(
    debounce(changeHandler, 300)
  , []);
Run Code Online (Sandbox Code Playgroud)

它说:

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

这就是说,即使debouncedChangeHandler由于 重新渲染而保持不变useCallback,但debounce(changeHandler, 300)仍会在每次渲染上执行。

但与useMemo

  const debouncedChangeHandler = useMemo(
    () => debounce(changeHandler, 300)
  , []);
Run Code Online (Sandbox Code Playgroud)

它声称:

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

因为useMemoLikeuseCallback不直接调用,而是在内联函数中debounce调用它。


运行这段代码:

let fakeDebounce = (param) => {
  console.log(param);
  return () => {};
};

export default function App() {
  let f = React.useCallback(fakeDebounce('test1'), []);
  let g = React.useMemo(() => fakeDebounce('test2'), []);
  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>
  );
}
Run Code Online (Sandbox Code Playgroud)

单击div任意位置即可查看如何test2不再记录。