React学习笔记—JSX

所谓JSX,是JavaScript的语法扩展(eXtension),让我们在JavaScript中可以编写像HTML一样的代码。

JSX中的这几段代码看起来和HTML几乎一摸一样,都可以使用<div><button>之类的元素,所以只要熟悉HTML,学习JSX完全不成问题,但是,我们一定要明白两者的不同之处。

首先,在JSX中使用的“元素”不局限于HTML中的元素,可以是任何一个React组件。例如:

// Counter组件
import React, { Component } from 'react';

class Counter extends Component {

  constructor(props) {
    super(props);
    this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
    this.onClickDecrementButton = this.onClickDecrementButton.bind(this);
    this.state = {
      count: props.initValue
    }
  }

  onClickIncrementButton() {
    this.setState({count: this.state.count + 1});
  }

  onClickDecrementButton() {
    this.setState({count: this.state.count - 1});
  }

  render() {
    const {caption} = this.props; 
    console.log(caption)
    return (
      <div>
        <button style={buttonStyle} onClick={this.onClickIncrementButton}>+</button>
        <button style={buttonStyle} onClick={this.onClickDecrementButton}>-</button>
        <span>{caption} count: {this.state.count}</span>
      </div>
    );
  }
}

Counter.defaultProps = {
  initValue: 0
};

export default Counter;

// ControlPanel组件
import React, { Component } from 'react';
import Counter from './Counter.js';

class ControlPanel extends Component {
  render() {
    return (
      <div style={style}>
        <Counter caption="First"/> 
        <Counter caption="Second" initValue={10} />
        <Counter caption="Third" initValue={20} />
      </div>
    );
  }
}

export default ControlPanel;

在ControlPanel组件中可以看到,创建的Counter组件被直接应用在了JSX中,使用方法和其他元素一样,这一点是传统的HTML做不到的。

React判断一个元素是HTML元素还是React组件的原则就是看第一个字母是否大写,如果在JSX中我们不使用Counter而是使用counter就得不到想要的结果。

其次,在JSX中可以通过onClick这样的方式给一个元素添加一个事件处理函数,当然,在HTML中也可以用onclick(注意和onClick拼写有区别),但在HTML中直接书写onclick一直就是为人诟病的写法,网页应用开发界面一直倡导的是用jQuery的方法添加事件处理函数,直接写onclick会带来代码混乱的问题。

这就带来一个问题,既然长期以来不倡导在HTML中使用onclick,为什么在React的JSx中我们却要使用onclick这样的方式来添加事件处理函数呢?

在React出现之初,很多人对React这样的设计非常反感,因为React把类似HTML的标记语言和JavaScript混在一起了,但是,随着时间的推移,业界逐渐认可了这种方式,因为大家都发现,以前用HTML来代表内容,用CSS代表样式,用JavaScript来定义交互行为,这三种语言分在三种不同的文件里面,实际上是把不同技术分开管理了,而不是逻辑上的“分而治之”。

根据做同一件事的代码应该有高耦合性的设计原则,既然我们要实现一个Counter,为什么不把实现这个功能的所有代码集中在一个文件里呢?

那么,JSX中使用onClick添加事件处理函数,是否代表网页应用开发兜了一个大圈,最终回到了起点了呢?

不是这样,在JSX中使用onClick添加事件处理方式和onclick有很大不同。 即使现在,我们还是要说在HTML中直接使用onclick很不专业,原因如下:

  1. onclick添加的事件处理函数是在全局环境下执行的,这污染了全局环境,很容易产生意料不到的后果;
  2. 给很多DOM元素添加onclick事件,可能会影响网页的性能,毕竟,网页需要的事件处理函数越多,性能就越低。
  3. 对于onclick的DOM元素,如果要动态地从DOM树种删掉的话,需要把对应的事件处理函数注销,假如忘了注销,就可能造成内存泄漏,这样的bug很难被发现。

上面说的这些问题,在JSX中都不存在。

首先,onClick挂载的每个函数,都可以控制在组件范围内,不会污染全局空间。以上面的Counter组件为例:

image.png

我们在Counter的JSX中使用了onClick,但并没有产生直接使用的onclick(注意是onclick不是onClick)的HTML,而是使用了事件委托(event delegation)的方式处理点击事件,无论有多少个onClick出现,其实最后都只在DOM树上添加了一个事件处理函数,挂在最顶层的DOM节点上。所有的点击事件都被这个事件处理捕获,然后根据具体组件分配给特定函数,使用事件委托的性能当然要比每个onClick都挂载一个事件处理函数要高。

因为React控制了组件的生命周期,在unmount的时候自然能够清除相关的所有事件处理函数,内存泄漏也不再是一个问题。

除了在组件中定义交互行为,我们还可以在React组件中定义样式,我们可以修改Counter组件中的render函数,代码如下:

import React, { Component} from 'react';

const buttonStyle = {
  margin: '10px'
};

class Counter extends Component {

  constructor(props) {
    super(props);
    this.onClickIncrementButton = this.onClickIncrementButton.bind(this);
    this.onClickDecrementButton = this.onClickDecrementButton.bind(this);

    this.state = {
      count: props.initValue
    }
  }

  onClickIncrementButton() {
    this.setState({count: this.state.count + 1});
  }

  onClickDecrementButton() {
    this.setState({count: this.state.count - 1});
  }

  render() {
    const {caption} = this.props; 
    console.log(caption)
    return (
      <div>
        <button style={buttonStyle} onClick={this.onClickIncrementButton}>+</button>
        <button style={buttonStyle} onClick={this.onClickDecrementButton}>-</button>
        <span>{caption} count: {this.state.count}</span>
      </div>
    );
  }
}

Counter.defaultProps = {
  initValue: 0
};

export default Counter;

可以看到React的组件可以把JavaScript、HTML和CSS的功能集中在一个文件中,实现真正的组件封装。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏老马寒门IT

02Vue.js快速入门-Vue入门之数据绑定

Vue框架很核心的功能就是双向的数据绑定。 双向是指:HTML标签数据 绑定到 Vue对象,另外反方向数据也是绑定的。通俗点说就是,Vue对象的改变会直接影响到...

2775
来自专栏游戏杂谈

DOM的事件模拟

只有根据DOM2级事件实现这些事件的浏览器才返回true,以非标准方式支持这些事件的浏览器会返回false;

1411
来自专栏Java帮帮-微信公众号-技术文章全总结

WAI-ARIA无障碍网页应用属性完全展示

WAI-ARIA指无障碍网页应用。主要针对的是视觉缺陷,失聪,行动不便的残疾人以及假装残疾的测试人员。尤其像盲人,眼睛看不到,其浏览网页则需要借助辅助设备,如屏...

2714
来自专栏hightopo

原 基于 HTML5 Canvas 的 3

1525
来自专栏向治洪

React Native之样式

样式 React Native 不实现 CSS,而是依赖于 JavaScript 来为你的应用程序设置样式。这是一个有争议的决定,你可以阅读那些幻灯片,了解...

2245
来自专栏HT

基于 HTML5 Canvas 的 3D 碰撞检测

这是公司大神写的一个放官网上给用户学习的例子,我一开始真的不知道这是在干嘛,就只是将三个形状图元组合在一起,然后可以同时旋转、放大缩小这个三个图形,点击“Ani...

2315
来自专栏阮一峰的网络日志

如何做到 jQuery-free?

jQuery是现在最流行的JavaScript工具库。 据统计,目前全世界57.3%的网站使用它。也就是说,10个网站里面,有6个使用jQuery。如果只考察使...

3204
来自专栏郭少华

(第一季)Vue2.0-内部指令

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核...

1203
来自专栏阿炬.NET

按键精灵-常用脚本命令汇集

3689
来自专栏移动开发面面观

React Native的动画(一)

1365

扫码关注云+社区

领取腾讯云代金券