简体   繁体   English

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

[英]Why use useMemo and not useCallback here?

So as i understand the difference between the two is that useCallback is used if a function or object or array is returned while useMemo when a primitive is returned.因此,据我了解,两者之间的区别在于,如果在返回原语时返回 useMemo 时返回 function 或 object 或数组,则使用 useCallback。 But i was looking up debouncing (this is the article: https://dmitripavlutin.com/react-throttle-debounce/ and it said useMemo would be a better solution. With useCallback但我正在查找去抖动(这是文章: 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>
  );
}

With useMemo用 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>
  );
}

And i don't understand.我不明白。 Is debounce returning a primitive value? debounce 是否返回原始值? If not how can we use useMemo?如果不是,我们如何使用 useMemo? Also how is useMemo better than useCallback here?还有这里的 useMemo 比 useCallback 好在哪里?

First about your quote:首先关于你的报价:

useCallback is used if a function or object or array is returned while useMemo when a primitive is returned如果返回原语时返回 function 或 object 或数组,则使用 useCallback

No, this is wrong.不,这是错误的。 useCallback is mainly for memoizing functions. useCallback主要用于记忆函数。 useMemo helps to avoid expensive calculations on every render. useMemo有助于避免在每次渲染时进行昂贵的计算。


Now for the article.现在来看这篇文章。 That article prefers useMemo for a different reason, that of performance;那篇文章更喜欢useMemo的另一个原因是性能。 although I doubt in most such cases the performance difference will be noticeable.尽管我怀疑在大多数此类情况下性能差异会很明显。

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

It says:它说:

However... this implementation has a small performance issue: each time the component re-renders, a new instance of the debounced function is created by the debounce(changeHandler, 300) .然而......这个实现有一个小的性能问题:每次组件重新渲染时, debounce(changeHandler, 300) 创建一个去抖动 function 的新实例

It is saying that even though the debouncedChangeHandler remains the same across re renders due to useCallback , the debounce(changeHandler, 300) is still executed on each render.也就是说,即使debouncedChangeHandler由于useCallback在重新渲染中保持不变, debounce debounce(changeHandler, 300)仍然在每次渲染时执行。

But with useMemo :但是使用useMemo

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

it claims:它声称:

useMemo(() => debounce(changeHandler, 300), []) memoizes the debounced handler, but also calls debounce() only during initial rendering of the component. useMemo(() => debounce(changeHandler, 300), []) 记忆去抖处理程序,但也仅在组件的初始渲染期间调用 debounce()

That is the reason why the article prefers useMemo .这就是文章更喜欢useMemo的原因。


Run this code:运行此代码:

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>
  );
}

Click div anywhere and see how test2 isn't logged anymore.在任意位置单击div并查看test2如何不再记录。

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

in every render:在每个渲染中:

  1. debounce(changeHandler, 300) will run(it is not a function, it is a called function) and resolve into a value(which is a callback) debounce(changeHandler, 300)将运行(它不是 function,它是一个被调用函数)并解析为一个值(这是一个回调)
  2. then useCallback will run, check the the dependency to determine whether it should return memoized value or new value, so in your case, it will return memoized value然后 useCallback 将运行,检查依赖关系以确定它是否应该返回记忆值或新值,所以在你的情况下,它将返回记忆值
  const debouncedChangeHandler = useMemo(
    () => debounce(changeHandler, 300)
  , [])

in every render在每次渲染中

  1. () => debounce(changeHandler, 300) will not run, it is value(callback) () => debounce(changeHandler, 300)不会运行,是 value(callback)
  2. then useMemo will run, it will check the dependency to determine whether to run the callback or not, in your case, it will not run the callback然后 useMemo 将运行,它将检查依赖关系以确定是否运行回调,在您的情况下,它不会运行回调

if you want to return a value, use useMemo if you use useMemo, it will cause side effect, which makes code look bad.如果你想返回一个值,使用useMemo如果你使用useMemo,它会产生副作用,让代码看起来很糟糕。 if you want to return a callback,use useCallback如果你想返回一个回调,使用useCallback

A great article on differnce between useMemo and useCallback https://medium.com/@jan.hesters/usecallback-vs-usememo-c23ad1dc60关于 useMemo 和 useCallback https://medium.com/@jan.hesters/usecallback-vs-usememo-c23ad1dc60之间差异的精彩文章

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 useCallback 与 useMemo 以及何时使用它们 - useCallback vs. useMemo and when to use them 何时使用 useMemo 和 useCallback 进行性能优化? - When to use useMemo and useCallback for performance optimization? 我的 useMemo useCallback 不会减少渲染次数。 使用 useMemo 和 useCallback 的正确方法是什么? - My useMemo useCallback does not reduce the number of render. What is the correct way to use useMemo and useCallback? useMemo(()=&gt;()=&gt;{}, []) 和 useCallback(()=&gt;{}, []) 一样吗? - Is useMemo(()=>()=>{}, []) the same as useCallback(()=>{}, [])? 在组件道具中使用 React.useMemo 或 React.useCallback 好吗? - Is good to use React.useMemo or React.useCallback inside component props? 为什么这段代码同时使用 useMemo 和 createSelector? - Why does this code use both useMemo and createSelector? 在自定义 hooks 中使用 useCallback 和 useMemo 的要点 - The point of using useCallback and useMemo in custom hooks React class 组件是否有等效于 UseMemo 或 UseCallback 的组件? - Is there an equivalent to UseMemo or UseCallback for React class component? React Docs以及useMemo和useCallback之间的区别 - React Docs and difference between useMemo and useCallback 在 React 中 useCallback/useMemo 有什么作用? - What does useCallback/useMemo do in React?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM