React Hooks的“穷举法”皮棉规则

时间:2019-11-14 21:28:53

标签: reactjs react-hooks eslint

很难理解'详尽的下降'棉绒规则

我已经读过关于stack1stack2的信息,但是我无法得到答案。

基本上,这是一个带有绒毛问题的简单react组件:

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

为什么皮棉?关于第一个示例的皮棉规则有任何清楚的解释吗?

或者我不应该在这里使用useEffect吗? (我是一个带钩的菜鸟)

2 个答案:

答案 0 :(得分:4)

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的{​​{1}}事件的效果。因此,我确实认为您同时调用<input>onChange的第二个版本比较惯用。

如果还有其他设置值的方法(例如,清除按钮),则经常不得不记住调用setValue可能很麻烦,所以我可以这样写:

onChange

但是在这一点上,这是头发劈开。

答案 1 :(得分:2)

exhaustive-deps警告的主要目的是防止开发人员丢失其效果内的依赖关系并丢失某些行为。

Dan abramov – Facebook核心开发人员– strongly recommend to keep that rule enabled

对于将函数作为依赖项传递的情况, React FAQ中有专门的章节

https://reactjs.org/docs/hooks-faq.html#is-it-safe-to-omit-functions-from-the-list-of-dependencies

tl; dr

如果必须在依赖项数组中放置一个函数:

  • 将函数放置在组件之外,因此可以确保不会在每个渲染器上更改引用。
  • 如果可以,请在效果之外调用该函数,然后仅将结果用作依赖项。
  • 如果必须在组件范围中声明函数,则必须使用useCallback钩子来记住函数引用。仅当回调函数的依存关系发生更改时,引用才会更改。