【问题标题】:Designing React Hooks prevent react-hooks/exhaustive-deps warning设计 React Hooks 可以防止 react-hooks/exhaustive-deps 警告
【发布时间】:2020-01-18 21:02:45
【问题描述】:

我正在设计一个钩子,仅当钩子依赖项发生变化时才获取数据。 它按预期工作,但我收到了 linter 警告:

React Hook useEffect was passed a dependency list that is not an array literal. This means we can't statically verify whether you've passed the correct dependencies.

React Hook useEffect has missing dependencies: 'data', 'errorHandler', 'route', and 'successHandler'. Either include them or remove the dependency array. If 'successHandler' changes too often, find the parent component that defines it and wrap that definition in useCallback. 

据我所知,我不想在我的依赖项中包含所有这些变量,因为我不想在这些更改时触发此钩子,我只想在我传递的依赖项更改时触发它。

问题: 如何以符合 hooks linter 标准的方式设计useFetch() hook(如果我的设计模式不符合标准,请详细说明应该如何最好地完成)。

我的useFetch()钩子

function useFetch(
    {
        route,
        data = {},
        successHandler,
        errorHandler,
    },
    dependencies = []) {
    const [loading, setLoading] = useState(true);
    useEffect(() => {
        setLoading(true);
        postJson({route}, data)
            .then(
                res => {
                    if(isFunction(successHandler)) successHandler(res);
                },
                ({responseJSON: err}) => {
                    if(isFunction(errorHandler)) {
                        errorHandler(err);
                    } else {
                        notify({text: err.message || messages.saveFailed(), cssClass: 'error'});
                    }
                }
            )
            .finally(() => {
                setLoading(false);
            });
    }, dependencies);
    return loading;
}

组件使用useFetch()

function MyComponent({data, selectedReviewId, setField}) {
    const loading = useFetch({
        route: 'foo.fetchData',
        data: {crrType, clientId, programId, userId},
        successHandler: d => setField([], d) // setField() will set data with the value fetched in useFetch() 
    }, [selectedReviewId]);

    return loading ? <SpinnerComponent/> : <div>{data.foo}</div>;
}

【问题讨论】:

  • 我的建议是,无论如何你有静态分配空数组给依赖变量,然后将该变量作为依赖数组提供,你应该直接提供空数组。另一个是不要破坏你的道具,你可以在 useEffect 直接使用props.dataprops.route

标签: javascript reactjs functional-programming react-hooks


【解决方案1】:

您已将依赖项作为数组传递,但在接收端,它本质上是一个指向数组的变量。 useEffect() 的 Lint 规则要求您在方括号中传递依赖项,如以下代码所示。

现在是一些技术性的东西。记住是什么产生了警告。它是语法检查代码的 lint。它不涉及语义。从语义上讲,您的依赖项列表是正确的,因为您正在传递一个数组,但在语法上,它没有作为数组传递,即它是一个未在方括号中传递的单个变量(例如 [dependencies])(这是 lint 正在寻找的东西)。所以为了满足 lint,你应该写:

useEffect(
  () => { // implementation of function },
  [dependencies]
);

此外,当您发送一个依赖数组时,您还可以使用扩展运算符,如下所示:

useEffect(
  () => { // implementation of function },
  [...dependencies]
);

这将通过 Babel 转译器在数组运算符中传播数组元素。 Lint 也会保持安静。

【讨论】:

  • 传播依赖会导致相同的结果:/,不过谢谢你的回答
  • 可能会有所不同。这取决于对依赖关系的反应有多深。如果它只是查看作为依赖项传递的变量的绑定,则数组传播似乎是更好的选择。如果 react 正在执行深度比较,那么只需在方括号内写入依赖项就足够了。
  • lint 规则不喜欢传播依赖,因此您仍然需要为文件或行禁用 lint 规则。
【解决方案2】:

eslint 警告是正确的 - 您应该将它们作为依赖项包含在内。例如,在您的MyComponent 中,如果data 发生更改,并且它不在您的依赖列表中,那么您的useEffect 钩子将调用fetch 将过时的data

同样适用于其他人 - 建议将这些添加到您的依赖项列表中。

对于第一个错误,它可能没问题 - 尽管并不理想。您有一个动态依赖项列表 - eslint 无法确定您是否拥有所有必需的东西。

您的解决方案可能会奏效 - 但它非常脆弱。如果您的dependencies 发生变化(例如,添加元素或移除元素)

【讨论】:

  • 你将如何解决它?
猜你喜欢
  • 2020-05-01
  • 2021-04-15
  • 2021-09-03
  • 1970-01-01
  • 2021-02-18
  • 2020-06-08
  • 2020-06-22
  • 2020-02-21
  • 2023-03-24
相关资源
最近更新 更多