Javascript React hooks-useffect deps-location.hash上的循环依赖

Javascript React hooks-useffect deps-location.hash上的循环依赖,javascript,reactjs,react-router,react-hooks,use-effect,Javascript,Reactjs,React Router,React Hooks,Use Effect,我有一个useffect,它读取位置。hash并基于一些其他依赖项,将更改hash。它看起来像这样: useEffect(() => { const hashAlreadyPresent = () => { const hashArr = history.location.hash.split('#'); return hashArr.includes(hashId); }; const addToHash = () => {

我有一个
useffect
,它读取
位置。hash
并基于一些其他依赖项,将更改hash。它看起来像这样:

useEffect(() => {
    const hashAlreadyPresent = () => {
      const hashArr = history.location.hash.split('#');
      return hashArr.includes(hashId);
    };

    const addToHash = () => {
      return history.location.hash.concat(`#${hashId}`);
    };

    const removeFromHash = () => {
      const hashArray = history.location.hash.split('#').filter(hashStr => hashStr);
      const indexOfHashId = hashArray.indexOf(hashId);
      (indexOfHashId !== -1) && hashArray.splice(indexOfHashId, 1);

      return hashArray;
    };

    // if hashId props is present then attach hash in route
    hashId && !hashAlreadyPresent() && history.push({
      hash: `${hashAlreadyPresent() ? '' : addToHash()}`,
      search: history.location.search,
    });

    return () => {
      // remove hashId only, retain any other hash if present
      const hashArray = removeFromHash();
      hashId && hashAlreadyPresent() && history.replace({
        hash: hashArray.join('#'),
        search: history.location.search,
      });
    };
  }, [history, hashId, history.location.hash, history.location.search]);
    
其中
历史记录
来自React路由器

逻辑是,一旦组件出现在屏幕上(挂载),它将向URL添加一个哈希,一旦卸载,它将从URL中删除哈希

当然,就useffect而言,它的意思是:如果任何依赖项发生了变化,那么之前的效果将被清除,并且效果的新实例将就位。有效的deps规则在这方面帮助了我,因为之前我忽略了一个事实,即如果
hashId
发生变化,应该清理并重新运行这个钩子

现在,我们应该依赖于
history.location.hash
来获得详尽的DEP,但问题是每次我从钩子中更改
hash
,钩子都会再次运行(前面的实例将再次清理并更改
hash
),这将导致无限更新类型的场景

注意:我知道这可以通过关闭deps规则并从依赖项中排除
history.location.hash
来实现,但我想找出重构/分解
useffect
的任何可能性,以便在不关闭它的情况下解决这个问题

另一件需要注意的事情是,如果我将
history
添加为依赖项(我必须这样做,因为我使用的是
history
中的方法),那么规则不会要求我显式添加嵌套的依赖项(
history.lcoation.search
history.location.hash
),但是,应该添加它们,由于
历史
对象将保持不变,但嵌套对象将随url更改而更改。这与将complete
props
对象指定为依赖项而不是仅指定所需的特定嵌套属性的用例相同

我是否应该在useEffect中设置一个基于位置更改的条件,该条件可以告诉我位置是否从钩子内部更改,因此不做任何事情

我是否应该以不同的方式分解并指定依赖项,以便在效果中更改location.hash时效果不会运行

注意: 在github上对此进行了讨论。有更多的见解。

指定非空依赖项数组时,添加到依赖项数组中的任何值都会首先运行清理函数(第一次渲染时除外),然后运行效果函数(卸载期间除外)。若要确定某个值是否应进入依赖项数组,请尝试回答该值的以下问题:

更新此值时,应再次运行效果,以便:

  • 观察到了预期的效果
  • 如有必要,将清除之前所做的任何潜在更改
  • 没有引入因过时引用而导致的错误
如果以上任何一点的答案都是“是”,那么该值将被添加到依赖项数组中

现在,我们可以为
useffect
函数中使用的所有值回答上述问题:

  • hashId
    。这是效果的主要驱动因素,每次该值更改时,URL都应反映更改。这成为效果的真实来源。因此,这是确保达到预期效果所必需的。此外,清理以前的
    hashId
    也需要这样做,因为清理函数需要引用以前的
    hashId
  • 历史记录
    。我认为,由于这是由react router提供的,所以在组件的整个生命周期中,引用不应该改变。从这个意义上讲,在这里添加它的唯一目的是满足lint规则,没有实际影响(除了额外的引用检查)。但是,如果它确实发生了更改,effect函数将有一个过时的引用,这可能会导致bug。这件事必须处理好
  • 历史记录.位置.搜索
    。这与主要效果无关,因为只需要
    hashId
    即可确保观察到所需的效果。也没有过时引用的危险,因为它总是从
    历史记录
    对象中读取。由于
    history
    对象是可变的,每次都用最新的值更新,并且已经是依赖项数组的一部分,因此可以安全地省略
    history.location.search
    *
  • history.location.hash
    ,用于与
    history.location.search
    相同的参数。此外,总是由
    hashId
    确定
    history.location.hash
    应该是什么,因此不应使用此值的更新来重新运行效果
最后一个依赖项数组就是
[hashId,history]
**


*小心不要从
历史记录中提取
搜索
。位置
,并在清理功能中使用
搜索
,因为这将是一个过时的引用


**注意到
routeModal
正在效果主体中使用,如果需要,这也必须是依赖项数组的一部分

已经删除了routeModal内容,如果让我们说我删除
历史记录,这是一个输入错误。推送
/
历史记录。从useEffect中替换
代码,lint规则将开始抱怨
history.location.hash
应该是一个依赖项,因此我认为删除
history.location.search
不应该满足详尽的deps,尽管在这种情况下它会起作用,就像在中一样,规则不会抱怨,因为父对象历史记录已在Dependencies中指定。但是我们