【问题标题】:How to solve jsx-no-bind error on a functional component?如何解决功能组件上的 jsx-no-bind 错误?
【发布时间】:2019-03-07 10:47:49
【问题描述】:

我有一个小组件来更改我网站的语言。由于 eslint 配置了jsx-no-bind,所以下面的代码会报错。

const ChangeLanguage = ({ toggleLanguage }) => {

    const toggle = () => {
        console.log('hi')
        toggleLanguage()
    }

    return (
        <IconButton
            onClick={toggle}
        >
            <Language /> // this is an svg-icon
        </IconButton>
    )
}

export default connect(null, { toggleLanguage })(ChangeLanguage)

我搜索了jsx-no-bind 的用法。有人说我们应该启用它,因为在每次渲染中,javascript 都会生成新函数,并且会导致不必要的渲染(如 airbnb 代码约定[link])。但是其他一些人说它的性能改进可以忽略不计,并且会降低代码的可读性(例如[link])。这里有两个问题:

  1. 如何解决错误(即不禁用jsx-no-bind)。
  2. 您对 jsx-no-bind 配置有什么建议(即我是否应该将其完全/部分从 eslint 配置中删除?)。

PS:有更多关于在网络中将箭头函数或绑定方法作为道具传递的文档。但我在问题陈述中只提到了其中两个。

【问题讨论】:

    标签: javascript reactjs jsx


    【解决方案1】:

    解决方案记录在这里:https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md#react-hooks

    函数式组件通常与钩子一起使用,如果您的回调完全独立于您的状态,则会发生最简单的情况。在这种情况下,解决方案就像将回调移出组件一样简单:

    const onClick = () => {
      console.log("Independent callback");
    };
    const Button = () => {
      return (
        <button type="button" onClick={onClick}>Label</button>
      );
    };
    

    否则,避免在每次渲染时重新定义回调的惯用方法是使用 useCallback 挂钩来记忆它们:

    const Button = () => {
      const [text, setText] = useState("Before click");
      const onClick = useCallback(() => {
        setText("After click");
      }, [setText]); // Array of dependencies for which the memoization should update
      return (
        <button type="button" onClick={onClick}>{text}</button>
      );
    };
    

    【讨论】:

      【解决方案2】:

      发生这种情况是因为您在组件的 return 语句中传递了一个函数,并且每次组件重新呈现时都会创建一个新函数。

      为避免这种情况,您只能使用它的参考。像这样,

      const ChangeLanguage = ({ toggleLanguage }) => {
      return (
          <IconButton
              onClick={toggleLanguage} // <----->
              <Language /> // this is an svg-icon
          </IconButton>
       )
      }
      

      export default connect(null, { toggleLanguage })(ChangeLanguage)

      【讨论】:

      • 你是对的。这里的问题解决了,但是如果我们必须将函数作为道具传递(在其他情况下)我们可以做什么......如何将函数作为 onClick 道具传递而不会出错(即不必要的渲染副作用)
      • 好吧,我个人没有遇到过“必须”在 return 语句中创建函数的情况,您可以在 return 或 render 方法之外定义函数并将其引用传递到内部。或者,如果失去了所有希望,您可以通过编写如下注释来禁用该文件的 eslint 规则:同一行:// eslint-disable-line jsx-no-bind 下一行:// eslint-disable-next-line jsx-no-bind 下面的所有代码: /* eslint-disable jsx-no-bind */
      • 我对代码稍作改动,但没有改变原来的问题。假设我们还必须/想要做其他事情(比如将字符串打印到控制台)...。问题依然存在!
      • 我相信因为它仍然在渲染内部,因为它是一个功能组件,如果你将它切换到一个基于类的组件,你可以在渲染方法之外定义函数并且它会起作用。我不确定useCallback()钩子是否绕过这个规则,建议你尝试/查找。
      • 感谢您对useCallback钩子的建议,我会看看的。但是对于第一部分,(因为它更好地定义功能组件而不是基于类)现在 Q 最好定义一个遵守 jsx-no-bind 规则的类或不遵守规则的功能组件?!
      【解决方案3】:

      如果我们这样做,eslint 不会抱怨:

      const ChangeLanguage = ({ toggleLanguage }) => {
      
          function toggle () {
              console.log('hi')
              toggleLanguage()
          }
      
          return (
              <IconButton
                  onClick={toggle}
              >
                  <Language /> // this is an svg-icon
              </IconButton>
          )
      }
      
      export default connect(null, { toggleLanguage })(ChangeLanguage)
      

      但我不确定有什么区别。在这种情况下,react 是不再在每个渲染上创建一个函数,还是只是规则不识别它?

      【讨论】:

        猜你喜欢
        • 2018-01-10
        • 1970-01-01
        • 2023-03-23
        • 2013-01-28
        • 2021-09-24
        • 2020-03-27
        • 2018-10-06
        • 2018-01-09
        • 1970-01-01
        相关资源
        最近更新 更多