首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >输入为空数组的`useCallback`和不带第二个参数的`useCallback`有什么区别?

输入为空数组的`useCallback`和不带第二个参数的`useCallback`有什么区别?
EN

Stack Overflow用户
提问于 2019-03-06 23:02:01
回答 2查看 20.5K关注 0票数 32

在我尝试更好地理解React Hooks的过程中,我遇到了一些我没有预料到的行为。我试图创建一个ref数组,并通过传递给我的<div>'s的onRef函数推送到所述数组。每次组件重新呈现时,数组都会变得越来越大,这可能只是因为它是一个简单的箭头函数,而不是内存。

因此,我添加了useCallback钩子,以确保我不会多次获得相同的ref,但令我惊讶的是,它仍然会在每次重新呈现时调用该函数。在添加一个空数组作为第二个参数后,refs只在每个组件中触发一次。

下面的代码片段演示了这种行为。

代码语言:javascript
复制
const Example = () => {
  const _refs = React.useRef([]);
  
  // Var to force a re-render.
  const [ forceCount, forceUpdate ] = React.useState(0);
  
  const onRef = (ref) => {
    if (ref && ref !== null) {
      console.log("Adding Ref -> Just an arrow function");
      _refs.current.push(ref);
    }
  }
  
  const onRefCallbackWithoutInputs = React.useCallback((ref) => {
    if (ref && ref !== null) {
      console.log("Adding Ref -> Callback without inputs.");
      _refs.current.push(ref);
    }
  });
  
  const onRefCallbackEmptyArray = React.useCallback((ref) => {
    if (ref && ref !== null) {
      console.log("Adding Ref -> Callback with empty array");
      _refs.current.push(ref);
    }
  }, []);
  
  React.useEffect(() => {
    console.log("Refs size: ", _refs.current.length);
  });
  
  return (
    <div>
      <div ref={onRef}/>
      <div ref={onRefCallbackWithoutInputs}/>
      <div ref={onRefCallbackEmptyArray}/>
      <div onClick={() => forceUpdate(forceCount + 1)} 
        style = {
          {
            width: '100px',
            height: '100px',
            marginTop: '12px',
            backgroundColor: 'orange'
          }
        }>
        {'Click me to update'}
       </div>
    </div>
  );
};

ReactDOM.render(<Example/>, document.getElementById('root'));
代码语言:javascript
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>

<div id='root' style='width: 100%; height: 100%'>
</div>

我假设useCallback会有一个空数组作为第二个参数的默认值。那么,不提供第二个参数到底有什么作用呢?为什么它的行为会有所不同?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-03-07 00:20:47

对于useMemouseCallback (本质上只是useMemo的特例),如果第二个参数是一个空数组,则该值将被记忆一次并始终返回。

如果省略第二个参数,该值将永远不会被记忆,并且useCallbackuseMemo不会执行任何操作。

也许在某些边缘情况下,你可能会有条件地记忆:

代码语言:javascript
复制
useMemo(someValue, shouldMemoize ? [] : null)

但在绝大多数情况下,useMemouseCallback的第二个参数都应该被认为是强制性的。事实上,是Typescript definitions treat them this way

代码语言:javascript
复制
// Require a second argument, and it must be an array
function useCallback<T extends (...args: any[]) => any>(callback: T, deps: DependencyList): T;

// Second argument can be undefined, but must be explicitly passed as undefined, not omitted.
function useMemo<T>(factory: () => T, deps: DependencyList | undefined): T;

有一个open pull request正在增强exhaustive-deps钩子的eslint规则,因此如果省略第二个参数,它将引发一个lint错误,所以很快这可能就是一个linter错误。

票数 54
EN

Stack Overflow用户

发布于 2020-11-16 23:38:45

我认为对于依赖数组的所有钩子,useEffectuseLayoutEffectuseCallbackuseMemo背后的逻辑是相同的,如果没有传递依赖项意味着我们传递了依赖项的空值,因此比较结果总是假的,内联函数每次都会执行。

如果传递的是空的依赖关系,则意味着没有进一步的比较,因此内联函数将只执行一次。(这就像我们指示React不做进一步的比较一样)。

如果数组传递了一些变量,那么它将根据变量的变化来计算内联函数。

尽管总是会创建内联函数的实例。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55026139

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档