React useEffect迫使我添加触发无限循环的依赖项

时间:2020-07-21 00:56:10

标签: reactjs use-effect

为什么React会用他们的linter插件强迫我添加我不想要的依赖项?

例如,我希望我的效果仅在certan值更改时才触发,但是linter告诉我在依赖项中添加偶数函数,而我不希望那样。

为什么强迫我这样做?我从中得到什么?

  /**
   * Gets all items, pages, until 250th.
   */
  useEffect(() => {
    let mounted = true;
    if (loadUntil250th && !paginationProps.complete) {
      mounted && setLoading(true);
      let limit = 250 - paginationProps.page * BATCH_LIMIT;
      fetchListItems(paginationProps, limit, paginationProps.page * BATCH_LIMIT)
        .then((results) => {
          if (mounted) {
            setPaginationProps({
              ...paginationProps,
              page: 250 / BATCH_LIMIT,
              autoLoad: false,
              complete: paginationProps.totalItems <= 250,
            });
            setListItems(results.listItems);
            setLoading(false);
          }
        })
        .catch((err) => {
          logger.log('LOADMORE FAILED:', err);
          mounted && setPaginationProps({ ...paginationProps, complete: true });
          mounted && setLoading(false);
        });
    }
    return () => {
      mounted = false;
    };
  }, [loadUntil250th]);

它想要这种依赖关系数组,从而导致无限循环

[loadUntil250th, logger, paginationProps, setListItems]);

如果我不想要它们,我想了解为什么要这么做。

1 个答案:

答案 0 :(得分:2)

“穷举-下降”棉绒规则旨在防范stale closures,其中useEffect引用回调中使用的道具或状态,但不存在于依赖项数组中。由于loggerpaginationPropssetListItems在理论上可以在渲染之间进行更改,因此在useEffect内引用它们而不将它们也包括在依赖项数组中以确保您可以始终接收最新数据并对其进行操作。您可以认为useEffect本质上是在创建状态和道具时生成所有状态和道具的快照,并在其依赖项之一发生更改时仅 对其进行更新。

例如,如果在依赖项列表中不包括paginationProps,则如果fetchListItems曾经修改过paginationProps的值,那么useEffect将无法访问该更新后的值loadUntil250th更改。

this answer中所述,部分问题是您对useEffect()的使用是 unidiomatic 。如果您要做的只是订阅对loadUntil250th的更改,最好将此功能移到其他位置,并使用修改loadUntil250th的代码来调用它。

如果要将代码保留在useEffect钩中,则可以选择以下几种方式:

  1. 假设paginationPropssetPaginationProps源自useState钩子,则可以通过passing a functionpaginationProps消除对setPaginationProps的依赖性而不是对象。因此您的代码将变为:
setPaginationProps(paginationProps => {
    ...paginationProps,
    page: 250 / BATCH_LIMIT,
    autoLoad: false,
    complete: paginationProps.totalItems <= 250,
});
  1. 如果可能,请移动setListItems inside the useEffect hook。这样可以确保您可以控制该功能所依赖的任何道具/状态。如果那不可能,那么您可以选择几种方法。您可以将函数完全移出组件,以确保它不依赖道具或状态。另外,您可以将useCallback hook与函数一起使用以控制其依赖性,然后将setListItems列为另一个依赖性。
  2. logger函数不太可能在渲染之间进行更改,因此您可以安全地将其保留在依赖项数组中(尽管linter期望这样做很奇怪)。

如果您仍然好奇,this article有助于详细说明useEffect和依赖项数组的实际工作方式。