Reactjs 我们在依赖项数组中使用的所有变量是否都有效?
我知道useEffect的依赖项是如何工作的。然而,在我的场景中,我不应该观察prop值的变化,我使用它作为处理流的条件,但是如果我不将它放在dependencies数组中,我将得到react hooks/deps警告 我的场景是,如果foo和fetchValue发生变化,我想重新运行整个fetch。虽然我使用bar作为条件来决定是否调用fechValue,但在我的业务逻辑中,bar的更改不应使块重新运行Reactjs 我们在依赖项数组中使用的所有变量是否都有效?,reactjs,react-hooks,Reactjs,React Hooks,我知道useEffect的依赖项是如何工作的。然而,在我的场景中,我不应该观察prop值的变化,我使用它作为处理流的条件,但是如果我不将它放在dependencies数组中,我将得到react hooks/deps警告 我的场景是,如果foo和fetchValue发生变化,我想重新运行整个fetch。虽然我使用bar作为条件来决定是否调用fechValue,但在我的业务逻辑中,bar的更改不应使块重新运行 const Component = ({ foo, bar, fetchValue })
const Component = ({ foo, bar, fetchValue }) => {
useEffect = (
() => {
if(foo) {
if (bar) {
fetchValue();
}
}
},
[foo, fetchValue] // will get a warning `react-hooks/exhaustive-deps`
)
return <div />
}
ESLint规则是为了确保useEffect挂钩的安全 如果绝对确定该值不是useEffect的依赖项,则可以添加注释以忽略ESLint规则: 我建议在下一行添加//eslint disable,而不是文件范围的eslint disable 这是: 是否有任何方法可以专门针对使用spread运算符的位置禁用此规则 如果您认为自己知道自己在做什么,则可以随时//eslint禁用下一行react hooks/deps
像这样的逻辑在“useffect”中的if语句中经常出现。首先,根本不需要添加依赖项,您可以将其保留为空 现在,您可以做一些事情,或者干脆忽略警告,因为您的代码看起来很好。或者重构代码,其中bar是fetchValue的参数。所以你的代码应该是:
const Component = ({ foo, bar, fetchValue }) => {
useEffect = (
() => {
if(foo) {
fetchValue(bar);
}
},
[foo, fetchValue]
)
return <div />
}
之所以要将所有使用的变量放入useEffects“deps”数组中,是因为不这样做可能会由于过时的数据而产生奇怪的问题 例如,给定您的用例,假设您的组件道具最初是{foo:false,bar:false}假设fetchValue是某个固定函数,然后它们更改为{foo:true,bar:true}。在这种情况下,组件将按预期调用fetchValue
但作为另一个例子,假设您的道具从{foo:false,bar:false}更改为{foo:true,bar:false},然后更改为{foo:true,bar:true}。在本例中,尽管道具与上一个示例末尾的道具相同,但fetchValue尚未激发 也许这本身并没有错,但它肯定是怪异和不直观的:理想情况下,您的组件应该基于其道具保持一致的行为,而不管道具的更改顺序如何 因此,是的,您可以始终忽略deps数组以使其不完整,但我个人建议寻找另一种解决方案
如果没有关于用例的更多信息,就很难说得具体,但是也许对fetchValue的调用可以被记忆,这样在foo没有改变的情况下它就不会做任何事情了?或者,foo和bar可以组合成一个单独的道具,这样它们就可以一起改变了?当然可以。我知道如何禁用警告。我只想讨论的是一些避免警告并以正确方式执行的伟大工具。该工具用于捕获常见用例中的bug,例如useEffect中使用的外部变量,它进行了一些优化以防止每次重新渲染时调用。您所描述的是一个边缘情况,该工具不支持它,因此您应该知道您正在做什么并禁用该规则。我提供了Dan Abramov的一条评论,解释了这一点。重构fetchValue并不能解决任何问题,因为代码仍然在useEffect中使用bar值。我支持第二部分,如果值在useEffect中不相关,那么代码可能会被重构以删除它在useEffect中的用法。您的两个示例仍然会提出相同的linter警告,将道具移动到状态通常不是一个好主意。这意味着组件将完全忽略对这些道具的更改,这通常是不需要的。也许我当时做了一些奇怪的事情,因为当我在一个类似的用例中偶然发现这个警告,后来不得不将道具更改为自定义延迟状态时,警告消失了:useEffect=>{if toggleComponents{const getElem=document.getElementByIdinputId;const getValue=getElem.value?getElem.value:getCheckedinputId;setValuegetValue;}setToggleComponentseditMode;}[editMode];这里没有警告。@Retsam你在做一个奇怪的论点。你说道具的改变不会影响useEffect,但不知怎么的,这可能是状态的问题?这是非常假设的,你能提供一个更具体的例子让我们展开吗?@MarkoGrešak第二个代码片段是一个具体的例子。通过复制foo i在初始渲染时,将忽略foo的所有未来值:useState只读取其默认值一次。这与UseEffect完全不同。假设您的道具从{foo:false,bar:false}更改为{foo:true,bar:false}它会在那里开火,据我所知,这就是@WendellLiu想要的。只是因为,然后变成{foo:true,bar:tr
ue}不需要触发。@Robbeoli useEffect将在那里触发,但fetchValue不会被触发,因为它被包装在ifbar中,而bar仍然是假的。哦,是的,这是真的,对我来说,这种使用感觉是直观的。我将bar视为确定获取值是否正确的某种状态,将foo视为需要为真的实际触发器,并检查bar状态是否为真。@Retsam如果bar是此组件中的一种状态,该怎么办?我是否需要将其添加到依赖项数组中以获取useEffect中的最新值?@NiyasNazar是-deps数组中唯一不需要包含的内容是在组件外部定义的内容,例如导入或模块级变量,以及由React状态设置器、分派函数保证为常量的内容,和ref objects。这听起来不像是一个有效的商业案例,更像是要求在将来调试竞争条件时遇到困难-请您详细描述一下为什么需要这样做?
const Component = ({ foo, bar, fetchValue }) => {
const [fooState, setFooState] = useState(foo);
const [barState, setBarState] = useState(bar);
useEffect = (
() => {
fooState && barState && fetchValue();
//does the same as your code, I just prefer short circuits for these kind of things.
},
[fooState, fetchValue()]
)
return <div />
}