javascript - 是否可以有条件地使用 useCallback React hook,即使它违反了 hooks 的规则?
问题描述
我试图找出一种方法来通过指定特定的道具来记忆 React 组件。
例如,如果你使用React.memo
- 它会根据所有 props 来记忆组件。
我想要实现的是能够将特定的道具作为依赖项传递给 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
这是我观察到的——</p>
- 我不应该
React.useCallback
在条件语句中使用或任何钩子,因为 React 需要知道调用钩子的顺序,并且在条件语句中使用它可能会在运行时弄乱顺序 - 但是
React.useCallback
在我的情况下工作得非常整洁,因为我知道在运行时顺序将保持不变 - 我没有在渲染期间使用条件语句中的钩子,而是在导出期间有条件地组合组件
- 我正在考虑将 React 组件视为普通的 JavaScript 函数,并尝试像记忆常规 JavaScript 函数一样记忆它
- 我可以很容易地替换
React.useCallback
为lodash.memoize
,最终结果将几乎相同 - 我不想使用外部库之类的
lodash.memoize
或构建自定义的记忆实现,而React.useCallback
几乎为我完成了工作
这是我不确定发生了什么的地方(这些是我的问题)-</p>
- React 组件并不是真正的原生 JavaScript 函数,我无法记住它们
lodash.memoize
lodash.memoize
并且React.useCallback
当我尝试记忆 React 组件时不一样- 即使在使用时,React 也会在确定渲染之前执行该函数
React.memo
(也许检查 prevProps 与 newProps?) - 即使它违反了 React 的规则,我的实现是否还可以?(在条件语句中使用钩子)
React.createElement
如果不是 for ,我还能如何记忆React.useCallback
?
我为什么要这样做的原因——</p>
我不想每次将处理程序(带有值和事件的闭包)传递给包装在React.memo
. 我希望能够以声明方式为组件编写 memoize 依赖项。
解决方案
React.memo
接受一个函数作为第二个参数来进行自定义道具比较。
默认情况下,它只会对 props 对象中的复杂对象进行浅层比较。如果要控制比较,还可以提供自定义比较函数作为第二个参数。
您可以像这样在您的 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"]);
推荐阅读
- javascript - 如何在不更改 html 字体大小的情况下使文本框变大?
- mlflow - mlflow 不支持 adbazureml
- xml - TALLY - http 标头 DISABLELOG 未禁用 http 日志记录
- python - 即使设置了套接字超时,SMTPLIB 超时也不起作用
- python - ValueError:传递值的长度为0,索引意味着11?
- regex - 用于开始和结束单词的 Python 正则表达式
- snowflake-cloud-data-platform - 有没有办法查看失败查询的查询配置文件?
- c# - 如何在 c# 中将我的文本文件拆分为带有分隔符的二维数组?
- excel - Excel Power Query - 使用 M 检查日期列表中的日期
- php - 使用 CloudFlare 启用强制 WWW 重定向会丢弃 POST 请求