【问题标题】:Why is react react-hooks/exhaustive-deps changing my code?为什么 react react-hooks/exhaustive-deps 会改变我的代码?
【发布时间】:2021-10-11 23:06:57
【问题描述】:

我想做这样的事情:

//snippet 1
const logFooOnlyOnce = (foo: string) => console.log(foo) //"...only once during the lifetime of this component"

export const MyComponent = ({ foo }: { foo: string }): JSX.Element => {
  React.useEffect(() => {
    logFooOnlyOnce(foo)
  }, []) //<-- error
  return <div />
}

即。我只想在特定范围内查看一次反应组件的道具。正如我所期望的那样,这段代码适用于普通的 JS。

但是 eslint 规则不允许我这样做。它改变了我的代码来做到这一点:

//snippet 2
import React from 'react'

const logFooOnlyOnce = (foo: string) => console.log(foo) //"...only once during the lifetime of this component"

export const MyComponent = ({ foo }: { foo: string }): JSX.Element => {
  React.useEffect(() => {
    logFooOnlyOnce(foo)
  }, [foo])
  return <div />
}

但这不是我想要的,如果foo 改变它的值,它会被记录不止一次。

不过,这似乎可行:

//snippet 3
const logFooOnlyOnce = (foo: string) => console.log(foo) //"...only once during the lifetime of this component"

export const MyComponent = ({ foo }: { foo: string }): JSX.Element => {
  const fooRef = React.useRef(foo)
  React.useEffect(() => {
    logFooOnlyOnce(fooRef.current)
  }, [])
  return <div />
}

如果 sn-p 3 有效,我可以忽略 snippet 1 中的空 dep 列表吗?我不想处理边缘情况,我想完全忽略它。

另外,我注意到这条规则在某种程度上可能会被欺骗:

//snippet 4
const logFooOnlyOnce = (foo: string) => console.log(foo) //"...only once during the lifetime of this component"
const myCallback = (foo: string) => () => {
  logFooOnlyOnce(foo)
}
export const MyComponent = ({ foo }: { foo: string }): JSX.Element => {
  React.useEffect(myCallback(foo), [])
  return <div />
}

还有这个:

//snippet 5
const logFooOnlyOnce = (foo: string) => console.log(foo) //"...only once during the lifetime of this component"
export const MyComponent = ({ foo }: { foo: string }): JSX.Element => {
  const myCallback = (foo: string) => () => logFooOnlyOnce(foo)
  React.useEffect(myCallback(foo), [])
  return <div />
}

为什么在这种情况下这条规则会抱怨,以及实现我想要的最干净的方法是什么? 为了应用eslint-ignore 指令,我需要有一个很好的案例来与更高的权力争论。

【问题讨论】:

  • 至少在 VSCode 中,原始代码应该被标记为错误。如果您将鼠标悬停在红色标记上,它应该会告诉您适用的规则,并且应该有一个选项可以忽略它。另请参阅此答案:stackoverflow.com/a/29592334/2740650
  • 我已经添加了解释。我不能在没有充分理由的情况下添加 eslint-ignore 指令。几天前我第一次看到这条规则,我试图弄清楚在特定情况下是否存在反对它的论点,以及我是否有特定情况。
  • 好的,至少现在你知道规则是“react-hooks/exhaustive-deps”。你可能想读这个:stackoverflow.com/questions/58866796/… 还有typeofnan.dev/…
  • 我已经通读了它,但它没有帮助:(“是因为 onChange 可以在渲染之间进行更改”当然,没关系,我想在它更改之前使用第一个版本,如果它改变了。
  • 在我看来,您似乎完全了解规则及其存在的原因,但您想做一些不寻常的事情。这正是ignore 的用途。但是如果你严格地想避免ignore,你可以存储一个布尔值,表明你已经用reactjs.org/docs/hooks-reference.html#useref记录了它

标签: reactjs react-hooks


【解决方案1】:

忽略规则,使用这条评论

// eslint-disable-next-line react-hooks/exhaustive-deps

例如

export const MyComponent = ({ foo }: { foo: string }): JSX.Element => {
  React.useEffect(() => {
    logFooOnlyOnce(foo)
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])
  return <div />
}

【讨论】:

  • 不幸的是,这可能不是一个选择(更高的权力),除非我能确切地论证为什么这将是一个值得的例外。
  • @pailhead,好吧,如果效果只运行一次符合您的利益,那么这是实现此目的的唯一方法。
  • @pailhead 您可能想为所说的“更高的权力”留下匿名便条,因为 eslint 规则不是一成不变的。当我写 react 时,我从不全局关闭这些规则;我用它们作为提醒,以确保我所做的事情是正确的,然后在很明显它们是错误的时候禁用它们。在这种情况下,规则要求您将 prop 添加到依赖项列表是错误的,因为这只会起到相反的效果(不是双关语)。 将规则视为建议,而不是法律
  • 这不是一成不变的,但必须有一个足够正当的理由。因为我实际上能够以相对轻松的方式重构它。所以我认为这个可能不是它:)
  • @pailhead,愿意分享你是怎么做到的吗?我有点好奇
【解决方案2】:

如果你不喜欢忽略规则,你也可以创建一个辅助函数来明确你想要什么,而不必在任何地方放置 eslint-disables:

import { EffectCallback, useEffect } from 'react';

const useEffectOnce = (effect: EffectCallback) => {
    useEffect(effect, []);
};

(你可以参考this,但是很短)

【讨论】:

  • 谢谢我真的很喜欢这种方法。至少从命名约定中可以清楚我想做什么。
猜你喜欢
  • 2020-05-01
  • 2021-04-15
  • 2020-06-08
  • 2022-10-20
  • 2020-03-11
  • 2020-01-18
  • 2023-03-24
相关资源
最近更新 更多