在 React 中处理事件的新方法

*Property Initializer Syntax*听起来比实际上更精彩,在这个大小的教程中,看看这种替代的方式写事件处理器将有助于消除你的构建器中的锅炉板,并在你的渲染器中防御不虚假的记忆使用。

在Facebook的文件中,你会看到事件处理是这样做的:

 1// option 1
 2class Thing extends React.Component {
 3  constructor() {
 4    this.handleSmthng = this.handleSmthng.bind(this)
 5  }
 6  render() {
 7    <input onChange={this.handleSmthng}/>
 8  }
 9  handleSmthng(e) {
10    // ...
11  }
12}

ES6类不会自动给这个范围给handsSmthng,因为你通常会想叫this.setState或可能在组件中呼吁另一种方法,官方的惯例是将所有事件处理器在constructor中的所有时间绑定在一起。


 1// option 2
 2class Thing extends React.Component {
 3  render() {
 4    <button onClick={() => this.handleSmthng('foo')}>
 5      ADD
 6    </button>
 7  }
 8  handleSmthng(arg1) {
 9    // ...
10  }
11}

这种模式似乎在React在线教程中变得越来越受欢迎。它将这个背景传递到handsSmthng,并避免在构建器中的锅炉板代码。哈哈,这个组件中没有状态,所以你甚至不需要构建器!我认为这种方法的动机是正确的......但性能成本很小。

使用箭头函数将始终在JavaScript中创建一个新的引用,这反过来会增加您的应用程序的内存使用量。虽然记忆在JavaScript中便宜,但在React中,渲染器很昂贵。当您将箭头函数传递给小组件时,您的小组件将无差别地重新渲染,因为(就它而言)箭头函数是新数据。

<$>[注] "...虽然如果这个回调作为低级组件的支持传递,这些组件可能会做额外的再渲染。

tiddly winks

两个关头,一个关头

有一个更干净的方式来编写事件处理器 1) 避免锅炉板和 2) 不会导致额外的重现: 属性初始化器语法)! 这是一个漂亮的名字,但这个想法非常简单......只需使用箭头函数来定义您的事件处理器。

 1class TodoApp extends React.Component {
 2  render() {
 3    return (
 4      <div>
 5        <button onClick={this.handleClick}>
 6          ADD
 7        </button>
 8        <input onChange={this.handleInput}/>
 9      </div>
10    );
11  }
12  handleClick = () => {
13    // "this"
14  }
15  handleInput = (e) => {
16    // "this", "e"
17  }
18}

你定义了两个处理器,它看起来非常漂亮. 没有锅炉板. 易于阅读. 易于重组...如果你想通过论点:

 1class TodoApp extends React.Component {
 2  render() {
 3    return (
 4      <div>
 5        <button onClick={this.handleClick}>
 6          ADD
 7        </button>
 8        <input onChange={this.handleInput}/>
 9        {
10          this.state.todos.map((item) => {
11            return (
12              <li onClick={this.handleRemove(item.id)}>
13                {item.text}
14              </li>
15            );
16          });
17        }
18      </div>
19    )
20  }
21
22  handleClick = () => {
23    // "this"
24  }
25
26  handleInput = (e) => {
27    // "this", "e"
28  }
29
30  handleRemove = (id) => (e) => {
31    // "this", "e", "id"
32  }
33}

蓬勃发展!你可以通过论点,而不使用绑定在你的渲染方法,或你的构建者! 一切看起来很棒。

如果你不习惯看到箭头函数,这可能看起来很奇怪。 请记住,在ES6中,脂肪箭头语法允许(https://alligator.io/js/arrow-functions/)为单行陈述(https://alligator.io/js/arrow-functions/)......它将暗示地返回在该行上的任何人! 这是巴贝尔将处理删除的方式:

1handleRemove: function (item) {
2  return function (e) {
3    // "item" AND "e" 🌈
4  }
5}

要将 Babel 配置为使用 Property Initializer Syntax,请确保安装了 transform-class-properties插件或 enable stage-2

<$>[注] 有一个 ESLint 规则,它会告诉你不要在渲染 <$> 中使用绑定或箭头函数

使用 Property Initializer 语法的优点

我的最佳猜测是,Facebook在他们的文档中没有正式支持这个模式是因为第二阶段ES6尚未完成,所以属性初始化器仍然被认为是非标准的。

一旦您熟悉 Property Initializers 并开始使用它们来定义处理方法,您将获得两个显着的好处:

  • 没有必要在构建器中写绑定陈述,现在你只是定义方法――而这就是它 ✨ 如果你需要通过论点,只需用单个关闭包装,并记得在渲染中召唤这个处理器函数作为一个额外的好处,如果你需要在其他地方重塑你的事件处理器,你只有一处可以剪贴
  • 较低的内存使用 在渲染中使用箭头函数是一个坏主意,因为按设计的渲染在组件生命周期中发生在高音量;为每个箭头函数分配一个新的指针。

点击此 CodePen 查看 Property Initializer 语法在行动

Published At
Categories with 技术
Tagged with
comments powered by Disqus