了解 React Hooks 'exhaustive-deps' lint 规则

问题描述 投票:0回答:3

我很难理解“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
? (我是个钩子小白)

reactjs react-hooks eslint
3个回答
165
投票

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>
    )
}

但在这一点上这是令人吹毛求疵的。


91
投票

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

tl;博士

如果您必须将函数放入依赖项数组中:

  • 将该函数放在组件之外,这样您就可以确保每次渲染时都不会更改引用。
  • 如果可以,请在效果之外调用该函数,然后将结果用作依赖项。
  • 如果必须在组件作用域中声明该函数,则必须使用
    useCallback
    钩子来记住函数引用。仅当回调函数的依赖关系发生变化时,引用才会发生变化。

0
投票

TL;博士

而不是

function X() {
    const myFunction = () => {
        ...
    }

    useEffect(()=> {
            myFunction();
    }, [myStateItem])
}

用途:

function X() {
    function myFunction() {
            ...
    }

    useEffect(()=> {
            myFunction();
    }, [myStateItem])
}
© www.soinside.com 2019 - 2024. All rights reserved.