如果我有一个钩子,例如:
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))
然后导致:
<块引用>React Hook "useGetSet"
不能在回调中调用。
必须在 React 函数组件或自定义 React Hook 中调用 React Hook
功能。
(反应钩子/钩子规则) eslint
为什么会有这种差异,它们不应该是等价的吗?
另外,如果这违反了钩子规则,应该怎么做?
答案 0 :(得分:2)
这两种情况都很糟糕,但 ESLint 没有处理第一种情况。
您可以通过在运行时更改标签数组来查看这一点。如果你增加或减少它爆炸的长度(因为根据异常调用了意外数量的钩子),如果你不这样做,它不会按预期重新渲染。 See here 获取演示的更新版本。
(规则存在的原因是因为在幕后,每次都需要以相同的顺序调用钩子。显然,如果每次渲染时钩子的数量不同,那么顺序就会改变。)
在您的特定情况下,因为您的数组是固定长度并且不会更改,所以您的代码将正常工作(无论 linter 怎么说)。但是,这仍然是一种危险的模式,最好避免。
就如何更好地处理它而言,如果您需要的不仅仅是基本状态管理,useReducer
之类的东西会起作用。您可以根据需要拥有任意数量的标签,并定义将标签作为参数的 setter/getter 操作。
答案 1 :(得分:1)
让我们分析这两种情况:
const labels = ['one', 'two'].map(useGetSet);
在这种情况下,useGetSet
在钩子内部被调用,称为“在自定义 React Hook 函数内部”。
const labels = ['one', 'two'].map((l) => useGetSet(l))
在这种情况下,useGetSet
是在匿名函数内部调用的,因此“钩子规则”被破坏了。
所以基本上:
在第一个场景中:Hook > 钩子的调用
第二种场景:Hook > 匿名函数 > 钩子的调用
关于最后一个问题:
<块引用>为什么会有这种差异,它们不应该是等价的吗?
不,它们不等价。
在第一种情况下,回调函数引用是您命名为 useGetSet
的函数。
在第二种情况下,回调函数引用是一个匿名定义的新函数。
有关此规则为何如此重要的有趣解释可以在文档中找到,特别是在本节中:
https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
但也要考虑到在某些情况下禁用 linter 规则是安全的,如这里深入解释的那样:
Why can't React Hooks be called inside loops or nested function?
答案 2 :(得分:0)
在这个例子中 useGetSet 是回调。
const labels = ['one', 'two'].map(useGetSet);
在这个例子中,你在回调中调用钩子,所以错误是有道理的。这个答案很好地说明了规则存在的原因:Why can't React Hooks be called inside loops or nested function?
const labels = ['one', 'two'].map((l) => useGetSet(l));
这里有两个选项: