React hooks-useEffect穷举deps-对位置的循环依赖.hash



我有一个useEffect,它读取location.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]);

其中CCD_ 3来自React Router。

逻辑是,一旦组件在屏幕上(安装),它就会向URL添加一个哈希,一旦卸载,它就会从URL中删除该哈希。

当然,就useEffect而言,它意味着:如果任何依赖项发生变化,则会清除以前的效果,并创建新的效果实例。有效的deps规则帮助我做到了这一点,因为之前我忽略了这样一个事实,即如果hashId发生变化,应该清理并重新运行这个钩子。

现在,对于穷举的deps,我们应该依赖history.location.hash,但问题是,每次我从钩子内更改hash时,钩子都会再次运行(上一个实例将清理并再次更改hash),这将导致一种无限更新的情况。

注意:我知道关闭穷举的deps规则并从依赖项中排除history.location.hash是可能的,但我想找出重构/分解useEffect的任何可能性,这样就可以在不关闭它的情况下解决这个问题。

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

我是否应该在我的useEffect中有一个基于位置何时更改的条件,它可以以某种方式告诉我位置是否从钩子内部更改,所以什么都不做?

我是否应该以不同的方式销毁并指定依赖项,以便在效果中更改位置.hash时不会运行效果?

注意:在github上对此进行了讨论。得到了更多的见解。https://github.com/facebook/react/issues/19636

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

当更新此值时,是否应再次运行效果,例如:

  • 观察到所需效果
  • 如有需要,将清理之前所做的任何潜在更改
  • 没有引入由于过时引用而导致的错误

如果上面任何一点的答案都是肯定的,那么该值将进入依赖数组。

我们现在可以回答上面关于useEffect函数中使用的所有值的问题:

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

那么最后的依赖数组就是history0。**


*注意不要从history.location中提取search,并在清除函数中使用search,因为它将是一个过时的引用

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

最新更新