即使useCallback React钩子违反了钩子规则,也可以有条件地使用吗?

时间:2019-05-07 09:08:43

标签: javascript reactjs react-hooks

我正在尝试通过指定特殊道具来记住React组件的方法。

例如,如果您使用React.memo-它会基于所有道具来记住组件。

我要实现的目标是能够将特定道具作为对util的依赖项(例如SuperMemo)进行传递,并将根据这些道具来记住组件。该方法非常类似于recompose -在导出之前先组成组件。

这是示例代码

import React from "react";

const isFunction = value =>
  value &&
  (Object.prototype.toString.call(value) === "[object Function]" ||
    "function" === typeof value ||
    value instanceof Function);

export const memo = (Comp, resolver) => {
  if (isFunction(resolver)) {
    const Memoized = props => {
      const deps = resolver(props);
      if (deps && deps.length) {
        // eslint-disable-next-line react-hooks/rules-of-hooks
        return React.useCallback(React.createElement(Comp, props), deps);
      }

      return React.createElement(Comp, props);
    };

    Memoized.displayName = `memoized(${Comp.name})`;
    return Memoized;
  }

  return React.memo(Comp);
};

export default memo;

这是将其用于组成组件的方式

import Todo from "./Todo";
import memo from "../memo";

export default memo(Todo, props => [props.text]);

我在这里有一个有效的代码框-memo-deps

这就是我观察到的-

  • 我不应该在条件语句中使用React.useCallback或任何钩子,因为React需要知道钩子的调用顺序,而在条件语句中使用它可能会在运行时弄乱顺序。
  • 但是React.useCallback在有条件的情况下非常整洁,因为我知道在运行时顺序将保持不变
  • 在渲染过程中,我没有在条件语句中使用钩子,而是在有条件的导出过程中对组件进行了组合
  • 我正在考虑将React组件作为普通的JavaScript函数使用,并试图像常规的JavaScript函数那样对其进行记忆
  • 我可以轻松地将React.useCallback替换为lodash.memoize,最终结果将几乎相同
  • 我不想使用lodash.memoize之类的外部库或构建自定义的回忆实现,而React.useCallback几乎可以为我完成工作

我不确定这是怎么回事(这是我的问题)—

  • 反应组件并不是真正的JavaScript函数,我无法用lodash.memoize来记住它们
  • 当我尝试记住一个React组件时,
  • lodash.memoizeReact.useCallback并不相同
  • 即使在使用React.memo的情况下,React也会在找出渲染之前执行该功能(也许是检查prevProps与newProps吗?)
  • 即使违反了React的规则,我的实现还可以吗? (在条件语句中使用钩子)
  • 如果不是React.createElement,我还能如何记住React.useCallback

我为什么要这样做的原因-

我不想每次将处理程序(带有值和事件的闭包)传递给包装在React.memo中的组件时都记住它们。我希望能够以声明方式编写组件的备注依赖。

1 个答案:

答案 0 :(得分:5)

React.memo接受一个函数作为第二个参数来进行自定义道具比较。

默认情况下,它只会浅浅比较道具中的复杂对象 目的。如果您想控制比较,还可以提供 自定义比较函数作为第二个参数。

您可以像这样在util函数中使用它:

export const memoWithSecondParam = (Comp, deps = []) => {
  return React.memo(Comp, (prevProps, nextProps) => {
    return deps.every(d => prevProps[d] === nextProps[d])
  });
};

并这样称呼它:

export default memoWithSecondParam(Todo, ["text"]);