了解 React Hooks 'exhaustive-deps' lint 规则 [英] Understanding the React Hooks 'exhaustive-deps' lint rule
问题描述
我很难理解 'exhaustive-deps' lint 规则.
I'm having a hard time understanding the 'exhaustive-deps' lint rule.
I already read this post and this post but I could not find an answer.
这是一个带有 lint 问题的简单 React 组件:
Here is a simple React component with the lint issue:
const MyCustomComponent = ({onChange}) => {
const [value, setValue] = useState('');
useEffect(() => {
onChange(value);
}, [value]);
return (
<input
value={value}
type='text'
onChange={(event) => setValue(event.target.value)}>
</input>
)
}
它需要我将 onChange
添加到 useEffect
依赖项数组.但在我的理解 onChange
永远不会改变,所以它不应该在那里.
It requires me to add onChange
to the useEffect
dependencies array. But in my understanding onChange
will never change, so it should not be there.
通常我是这样管理的:
const MyCustomComponent = ({onChange}) => {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
onChange(event.target.value)
}
return (
<input
value={value}
type='text'
onChange={handleChange}>
</input>
)
}
为什么会掉毛?关于第一个示例的 lint 规则有什么明确的解释吗?
Why the lint? Any clear explanation about the lint rule for the first example?
或者我不应该在这里使用 useEffect
吗?(我是一个有钩子的菜鸟)
Or should I not be using useEffect
here? (I'm a noob with hooks)
推荐答案
linter 规则希望 onChange
进入 useEffect
钩子的原因是因为 onChange
以在渲染之间进行更改,并且 lint 规则旨在防止这种陈旧数据"引用.
The reason the linter rule wants onChange
to go into the useEffect
hook is because it's possible for onChange
to change between renders, and the lint rule is intended to prevent that sort of "stale data" reference.
例如:
const MyParentComponent = () => {
const onChange = (value) => { console.log(value); }
return <MyCustomComponent onChange={onChange} />
}
MyParentComponent
的每次渲染都会将不同的 onChange
函数传递给 MyCustomComponent
.
Every single render of MyParentComponent
will pass a different onChange
function to MyCustomComponent
.
在您的特定情况下,您可能并不关心:您只想在值更改时调用 onChange
,而不是在 onChange
函数更改时调用.但是,从您如何使用 useEffect
来看,这并不清楚.
In your specific case, you probably don't care: you only want to call onChange
when the value changes, not when the onChange
function changes. However, that's not clear from how you're using useEffect
.
这里的根源在于您的 useEffect
有点单调.
The root here is that your useEffect
is somewhat unidiomatic.
useEffect
最适合用于副作用,但在这里您将其用作一种订阅"概念,例如:当 Y 更改时执行 X".由于 deps
数组的机制,这确实在功能上起作用(尽管在这种情况下,您还在初始渲染时调用了 onChange
,这可能是不需要的),但这不是预期的目的.
useEffect
is best used for side-effects, but here you're using it as a sort of "subscription" concept, like: "do X when Y changes". That does sort of work functionally, due to the mechanics of the deps
array, (though in this case you're also calling onChange
on initial render, which is probably unwanted), but it's not the intended purpose.
调用 onChange
在这里真的不是副作用,它只是触发 的
onChange
事件的效果.所以我确实认为你的第二个版本同时调用 onChange
和 setValue
更惯用.
Calling onChange
really isn't a side-effect here, it's just an effect of triggering the onChange
event for <input>
. So I do think your second version that calls both onChange
and setValue
together is more idiomatic.
如果有其他设置值的方法(例如清除按钮),不断地记住调用 onChange
可能会很乏味,所以我可以这样写:
If there were other ways of setting the value (e.g. a clear button), constantly having to remember to call onChange
might be tedious, so I might write this as:
const MyCustomComponent = ({onChange}) => {
const [value, _setValue] = useState('');
// Always call onChange when we set the new value
const setValue = (newVal) => {
onChange(newVal);
_setValue(newVal);
}
return (
<input value={value} type='text' onChange={e => setValue(e.target.value)}></input>
<button onClick={() => setValue("")}>Clear</button>
)
}
但在这一点上这是令人毛骨悚然的.
But at this point this is hair-splitting.
这篇关于了解 React Hooks 'exhaustive-deps' lint 规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!