*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中,渲染器很昂贵。当您将箭头函数传递给小组件时,您的小组件将无差别地重新渲染,因为(就它而言)箭头函数是新数据。
<$>[注] "...虽然如果这个回调作为低级组件的支持传递,这些组件可能会做额外的再渲染。
两个关头,一个关头
有一个更干净的方式来编写事件处理器 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 语法在行动