我很难理解“exhaustive-deps”lint 规则。
这是一个简单的 React 组件,存在 lint 问题:
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
永远不会改变,所以它不应该存在。
通常我是这样处理的:
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 规则有明确的解释吗?
或者我不应该在这里使用
useEffect
? (我是个钩子小白)
linter 规则希望
onChange
进入 useEffect
钩子的原因是因为 onChange
可能在渲染之间发生变化,而 lint 规则旨在防止这种“过时数据”引用。
例如:
const MyParentComponent = () => {
const onChange = (value) => { console.log(value); }
return <MyCustomComponent onChange={onChange} />
}
MyParentComponent
的每个渲染都会将不同的onChange
函数传递给MyCustomComponent
。
在您的具体情况下,您可能不在乎:您只想在值更改时调用
onChange
,而不是在 onChange
函数更改时调用。 但是,从您如何使用 useEffect
来看,这一点并不清楚。
这里的根源是你的
useEffect
有点不惯用。
useEffect
最适合用于副作用,但在这里您将其用作一种“订阅”概念,例如:“当 Y 更改时执行 X”。 由于 deps
数组的机制,这在功能上确实有效(尽管在这种情况下,您还在初始渲染时调用 onChange
,这可能是不需要的),但这不是预期目的。
调用
onChange
实际上并不是副作用,它只是触发 onChange
的 <input>
事件的效果。 所以我确实认为你的第二个版本将 onChange
和 setValue
一起调用更惯用。
如果有其他设置值的方法(例如清除按钮),不断地记住调用
onChange
可能会很乏味,所以我可能会写成:
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>
)
}
但在这一点上这是令人吹毛求疵的。
exhaustive-deps
警告的主要目的是防止开发人员丢失其效果内的依赖项并丢失某些行为。
Dan abramov – Facebook 核心开发人员 – 强烈建议保持该规则启用。
对于将函数作为依赖项传递的情况,React FAQ 中有专门的章节:
https://reactjs.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependency
如果您必须将函数放入依赖项数组中:
useCallback
钩子来记住函数引用。仅当回调函数的依赖关系发生变化时,引用才会发生变化。而不是
function X() {
const myFunction = () => {
...
}
useEffect(()=> {
myFunction();
}, [myStateItem])
}
用途:
function X() {
function myFunction() {
...
}
useEffect(()=> {
myFunction();
}, [myStateItem])
}