javascript - 为什么映射 React 钩子有效,但 lambda 违反钩子规则?
问题描述
如果我有一个钩子,例如:
const useGetSet = (label: string) => {
const [get, set] = useState(label);
return { get, set };
};
我可以map
在一个数组上,例如:
const labels = ['one', 'two'].map(useGetSet);
但是,如果我将其扩展为 lambda,例如:
const labels = ['one', 'two'].map((l) => useGetSet(l))
然后它导致:
"useGetSet"
不能在回调中调用React Hook 。
React Hooks 必须在 React 函数组件或自定义 React Hook 函数中调用。(react-hooks/rules-of-hooks) eslint
为什么会有这种差异,它们不应该是等价的吗?
另外,如果这违反了钩子规则,应该怎么做?
解决方案
这两种情况都很糟糕,但 ESLint 并没有选择第一种情况。
您可以通过在运行时更改标签数组来看到这一点。如果您增加或减少它爆炸的长度(因为根据例外情况调用了意外数量的钩子),如果您不这样做,它不会按预期重新渲染。有关演示的更新版本,请参见此处。
(规则存在的原因是因为在底层,每次都需要以相同的顺序调用钩子。显然,如果钩子的数量在渲染之间发生变化,那么顺序就会改变。)
在您的特定情况下,因为您的数组是固定长度并且不会更改,所以您的代码将正常工作(无论 linter 说什么)。但是,它仍然是一种危险的模式,最好避免。
就如何更好地处理它而言,如果您需要的不仅仅是基本状态管理,那么类似的东西useReducer
会起作用。您可以拥有任意数量的标签,并定义将标签作为参数的 setter/getter 操作。
推荐阅读
- c++ - Displaying results as soon as they are ready with std::async
- android - 我的代码没有在 firebase 实时数据库中上传一些大图片的 url。谁能帮我解决这个问题?
- php - 有没有办法“手动”将数据发送到 [woocommerce_checkout] 页面?
- java - 我是否需要自定义 Spliterator 以避免额外的 .stream() 调用?
- asp.net-core - 通过 TeamCity 将 asp.net 核心项目部署到具有不同环境(UAT、发布)的 IIS
- swift - 如何将相机或画廊拍摄的图像添加到按钮?
- ios - AlamoFire 5.0 强制永久缓存
- c# - 使用 C# 函数导出到缺少第一条记录的 CSV
- excel - 删除除特定范围外的公式
- javascript - 在 HTML5 网络存储中存储来自 jspdf 的文档元素