深入了解JSX

特别声明:为了感谢社区对W3cplus的支持,在毕业季到来之际,小站开启毕业季优惠,在2019年07月01日至2019年07月10日之间,年费价格为 ¥299.00元。如果您喜欢小站的内容,可以点击开通会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!(^_^)

最近开始学着使用React写东西。在写代码时会使用JSX,不了解JSX的相关知识写起代码的效率还是蛮低的。为了能更好的进入状态,打算先把JSX相关的知识和细节了解一下。在这篇文章中我们主要就是来学习一下JSX的相关知识。希望对于像我这样的初学React(或初次接触JSX)的同学有所帮助。

什么是JSX

JSX是JavaScript中的一种语法扩展。是React组件编写UI逻辑的语言扩展(JSX除了能在React中使用之外还可以用于别的地方)。虽然在不使用JSX的情况之下,React可以完全正常工作,但它是一种理想的组件处理技术,所以React从JSX中获益良多。

首先,你可能认为使用JSX就是将HTML和JavaScript混合在一起,事实并非如此,因为在使用JSX语法时,描述这个UI不是用字符串,使用的是JavaScript。这让我们能做很多事。

将JavaScript和标记(Markup)放在同一位置被认为是一种坏习惯,但事实证明,将视图与功能结合起来可以直接对视图进行推理。

为了了解这意味着什么,假设我们有一个React组件,它只渲染一个<h1>标签。JSX允许我们以种非常类似HTML的方式声明这个元素:

class HelloWorld extends React.Component {
    render() {
        return (
            <h1 className="title">Hello World</h1>
        )
    }
}

HelloWorld组件中的render()函数看起来返回的是HTML,但实际上这是JSX。JSX在运行时被转换为常规则JavaScript。翻译后的组件看起来是这样的:

class HelloWorld extends React.Component {
    render() {
        return (
            React.createElement(
                'h1',
                {className: 'title'},
                'Hello World'
            )
        )
    }
}

虽然JSX看起来像HTML,但实际上它只是一种编写React.createElement()声明的更简洁的方法。当组件渲染时,它输出一个React元素树或该组件输出的HTML元素的虚拟DOM。然后,React将根据这个React元素表示确定对实际DOM进行哪些更改。HelloWorld组件渲染出来的React的HTML看起来像下面这样:

<h1 class='title'>Hello World</h1>

为什么使用JSX

React认为渲染逻辑本质上与其他UI逻辑内在耦合,比如,在UI中需要绑定处理事件、在某些时刻状态发生变化时需要通知到UI,以及需要在UI中展示准备好的数据。

React并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为组件的松散耦合单元之中,来实现“关注点分离”。React不强制要求使用JSX,但大多数人发现,在JavaScript代码中将JSX和UI放在一起时,会在视觉上有辅助作用。它还可以使React显示更多有用的错误和警告消息。

JSX原理

在继续往下阅读之前,先稍微的了解一些有关于JSX原理相关的内容。即JSX是经过怎么样的转化变成页面的元素的

比如说下面这个最简单的DOM元素为例,怎么使用JavaScript的对象来表现一个DOM元素的结果:

<h1 class="title">Hello World!</h1>

每个DOM元素的结构都可以用JavaScript的对象来表示。你会发现,DOM元素包含的信息其实只有三个:标签名(HTML元素)属性(HTML元素属性)子元素(HTML元素或文本节点)。那么上面的这个HTML标签对应的所有信息可以用下面这个对象来描述:

{
    tag: 'div',
    attrs: {className: 'title'},
    children: 'Hello World!'
}

你会发现,HTML的信息和JavaScript所包含的结构和信息其实是一样的,我们可以用JavaScript对象来描述所有能用HTML表示的UI信息。只不过写起来有点麻烦,结构看起来不太清晰。

在React中会把类似HTML的JSX结构转换成JavaScript的对象结构。比如:

<h1 class="title">Hello World!</h1>

JSX转换成JavaScript就会像下面这样:

React.createElement(
    "h1", 
    {
        class: "title"
    }, 
    "Hello World!"
);

React.createElement()会构建一个JavaScript对象来描述HTML结构的信息,包括标签名属性子元素等。上面是一个较为简单的示例,对于复杂的示例,我们可以借助在线的工具来帮助我们,比如Babel

所谓的JSX其实就是JavaScript对象

有了之个表示HTML结构和信息的对象以后,就可以去构造真正的DOM元素,然后使用ReactDOM.render()函数把构造好的DOM元素塞到页面中:

ReactDOM.render(
    <HelloWorld />,
    document.getElementById('root')
)

ReactDOM.render()函数就是把组件渲染并且构造DOM树,然后插入到页面上某个特定的元素上div#root

简单地总结一下,JSX经过Babel编译和React构造器转换成了JavaScript对象,然后通过ReactDOM.render()函数转换成DOM元素,再插入到页面中渲染出来:

接下来简单看看JSX的具体使用。

JSX的使用

在JSX中可以像下面这样定义一个包含字符串的<h1>标签:

const element = <h1> Hello World!~</h1>

看起来有点像是JavaScript和HTML的结合特,但实际上它就是JavaScript。在JSX中是用来定义组件及其在标记中的位置的语法糖。事实element是一个Object

JSX中嵌入表达式

在下面的示例中,声明了一个名为eleId的变量,然后在JSX中使用它,并且放置在{}中,比如:

const eleId = 'title'
const element = <h1 id={eleId}>Hello World!</h1>

在JSX语法中,可以在大括号内放置任何有效的JavaScript表达式,比如:

const Hello = (user) => {
    return `Hello ${user}`;
}

const element = <h1>{ Hello('W3cplus.com') }</h1>

在属性中嵌入JavaScript表达式时,不要在大括号外面加上引号。应该仅使用引用(字符串)或大括号(表达式)中的一个,对于同一个属性不能同时使用这两种符号。

JSX中的特定属性

在HTML中标签中有时候会用到带有-中折号的属性,比如aira-hidden,也会有多个词组合在一起的属性,比如tabindex。类似这些属性在JSX中需要使用驼峰写法,比如airaHiddentabIndex

const eleId='title'
const element = <h1 id={eleId} tabIndex="0">Hello World!</h1>

需要特别注意的是,在JSX中要是会用到classfor属性时,需要将class换成 classNamefor换成 htmlFor。那是因为classfor是JavaScript中的关键字。

const element = (
    <div className="control">
        <label htmlFor="user">Name:</label>
        <input id="user" type="text" placholder="Enter your name" />
    </div>
)

在JSX中有些写法和HTML类似,比如一个标签里没有内容,可以使用/>来闭合标签,比如上面的<input>元素:

<input id="user" type="text" placholder="Enter your name" />

如果在ReactDOM.render()包含多个子元素时(JSX标签里包含多个子元素),需要用一个标签元素括起来,比如上面示例中的<div className="control">。另外将其放置在一个括号()中。这是因为render()函数只能返回一个节点,所以如果你想返回两个兄弟节点,就需要添加一个父节点,如上面示例所示。

JSX是一个对象

浏览器不能直接执行包含JSX代码的JavaScript文件。它们必须首先转换成普通的JavaScript。需要一个叫做转置的过程。当然,在React中JSX是可选的,因为对于每个JSX代码都有对应的纯JavaScript代码替代,这就是JSX的换位符

正如文章开头所提到的,Babel会把JSX转译成一个名为React.createElement()函数调用。比如下面的两段代码,起到的作用是同等的:

// JSX代码
ReactDOM.render(
    <div id="box">
        <h1>title</h1>
        <p>paragraph</p>
    </div>,
    document.getElementById('root')
)

// JavaScript
ReactDOM.render(
    React.createElement(
        "div", 
        {id: "box"},
        React.createElement(
            "h1", 
            null, 
            "title"
        ), 
        React.createElement(
            "p", 
            null, 
            "paragraph"
        )
    ), 
    document.getElementById('root')
);

JSX和JavaScript两段代码同样可以借助在线的Babel工具查看。

上面的示例也再次验证了,虽然JSX和JavaScript所起的效果是等效的,但相比而言,JavaScript要比JSX复杂的多。另外React.createElement()会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个这样的对象:

// 简化后的结构
React.createElement(
    "h1",
    null, 
    "title"
)

实际上,JSX仅仅只是React.createElement(component, props, ...children)函数的语法糖。如下JSX代码:

// JSX代码
<MyButton color="blue" shadowSize={2}>
    Click Me
</MyButton>

编译成JavaScript代码如下:

// JavaScript代码
React.createElement(
    MyButton, 
    {
        color: "blue",
        shadowSize: 2
    }, 
    "Click Me"
);

JSX中的JS

JSX接受任何混合的JavaScript。当你需要添加一些JavaScript时,只需要将它放到大括号{}中(前面也有简单的提到过)。例如,下面的示例就是向你展示了在JSX中怎么引用其他地方声明的常量:

const n
剩余80%内容付费后可查看
* 请输入阅读码(忘记阅读码?

如需转载,烦请注明出处:https://www.w3cplus.com/react/in-depth-understanding-of-jsx.html

如果文章中有不对之处,烦请各位大神拍正。如果你觉得这篇文章对你有所帮助,打个赏,让我有更大的动力去创作。(^_^)。看完了?还不过瘾?点击向作者提问!

赏杯咖啡,鼓励他创作更多优质内容!
返回顶部