深入了解JSX
什么是JSX
JSX是JavaScript中的一种语法扩展。是React组件编写UI逻辑的语言扩展(JSX除了能在React中使用之外还可以用于别的地方)。虽然在不使用JSX的情况之下,React可以完全正常工作,但它是一种理想的组件处理技术,所以React从JSX中获益良多。
首先,你可能认为使用JSX就是将HTML和JavaScript混合在一起,事实并非如此,因为在使用JSX语法时,描述这个UI不是用字符串,使用的是JavaScript。这让我们能做很多事。
将JavaScript和标记(Markup)放在同一位置被认为是一种坏习惯,但事实证明,将视图与功能结合起来可以直接对视图进行推理。
为了了解这意味着什么,假设我们有一个React组件,它只渲染一个
标签。JSX允许我们以种非常类似HTML的方式声明这个元素:
class HelloWorld extends React.Component {
render() {
return (
Hello World
)
}
}
Hello World
) } } 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看起来像下面这样:
Hello World
为什么使用JSX
React认为渲染逻辑本质上与其他UI逻辑内在耦合,比如,在UI中需要绑定处理事件、在某些时刻状态发生变化时需要通知到UI,以及需要在UI中展示准备好的数据。
React并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为组件的松散耦合单元之中,来实现“ 关注点分离 ”。React不强制要求使用JSX,但大多数人发现,在JavaScript代码中将JSX和UI放在一起时,会在视觉上有辅助作用。它还可以使React显示更多有用的错误和警告消息。
JSX原理
在继续往下阅读之前,先稍微的了解一些有关于JSX原理相关的内容。即 JSX是经过怎么样的转化变成页面的元素的 。
比如说下面这个最简单的DOM元素为例,怎么使用JavaScript的对象来表现一个DOM元素的结果:
Hello World!
每个DOM元素的结构都可以用JavaScript的对象来表示。你会发现,DOM元素包含的信息其实只有三个: 标签名(HTML元素) 、 属性(HTML元素属性) 和 子元素(HTML元素或文本节点) 。那么上面的这个HTML标签对应的所有信息可以用下面这个对象来描述:
{ tag: 'div', attrs: {className: 'title'}, children: 'Hello World!' }
你会发现,HTML的信息和JavaScript所包含的结构和信息其实是一样的,我们可以用JavaScript对象来描述所有能用HTML表示的UI信息。只不过写起来有点麻烦,结构看起来不太清晰。
在React中会把类似HTML的JSX结构转换成JavaScript的对象结构。比如:
Hello World!
JSX转换成JavaScript就会像下面这样:
React.createElement( "h1", { class: "title" }, "Hello World!" );
React.createElement()
会构建一个JavaScript对象来描述HTML结构的信息,包括 标签名 、 属性 和 子元素 等。上面是一个较为简单的示例,对于复杂的示例,我们可以借助在线的工具来帮助我们,比如 Babel :
所谓的JSX其实就是JavaScript对象。
有了之个表示HTML结构和信息的对象以后,就可以去构造真正的DOM元素,然后使用 ReactDOM.render()
函数把构造好的DOM元素塞到页面中:
ReactDOM.render( , document.getElementById('root') )
ReactDOM.render()
函数就是把组件渲染并且构造DOM树,然后插入到页面上某个特定的元素上 div#root
。
简单地总结一下,JSX经过Babel编译和React构造器转换成了JavaScript对象,然后通过 ReactDOM.render()
函数转换成DOM元素,再插入到页面中渲染出来:
接下来简单看看JSX的具体使用。
JSX的使用
在JSX中可以像下面这样定义一个包含字符串的
标签:
const element = Hello World!~
Hello World!~
看起来有点像是JavaScript和HTML的结合特,但实际上它就是JavaScript。在JSX中是用来定义组件及其在标记中的位置的语法糖。事实 element
是一个 Object
:
JSX中嵌入表达式
在下面的示例中,声明了一个名为 eleId
的变量,然后在JSX中使用它,并且放置在 {}
中,比如:
const eleId = 'title' const element =Hello World!
在JSX语法中,可以在大括号内放置任何有效的JavaScript表达式,比如:
const Hello = (user) => { return `Hello ${user}`; } const element ={ Hello('W3cplus.com') }
在属性中嵌入JavaScript表达式时,不要在大括号外面加上引号。应该仅使用引用( 字符串 )或大括号( 表达式 )中的一个,对于同一个属性不能同时使用这两种符号。
JSX中的特定属性
在HTML中标签中有时候会用到带有 -
中折号的属性,比如 aira-hidden
,也会有多个词组合在一起的属性,比如 tabindex
。类似这些属性在JSX中需要使用驼峰写法,比如 airaHidden
或 tabIndex
。
const eleId='title' const element =Hello World!
需要特别注意的是,在JSX中要是会用到 class
和 for
属性时,需要将 class
换成 className
, for
换成 htmlFor
。那是因为 class
和 for
是JavaScript中的关键字。
const element = ()
在JSX中有些写法和HTML类似,比如一个标签里没有内容,可以使用 />
来闭合标签,比如上面的 元素:
如果在 ReactDOM.render()
包含多个子元素时(JSX标签里包含多个子元素),需要用一个标签元素括起来,比如上面示例中的
()
中。这是因为 render()
函数只能返回一个节点,所以如果你想返回两个兄弟节点,就需要添加一个父节点,如上面示例所示。
JSX是一个对象
浏览器不能直接执行包含JSX代码的JavaScript文件。它们必须首先转换成普通的JavaScript。需要一个叫做 转置 的过程。当然,在React中JSX是可选的,因为对于每个JSX代码都有对应的纯JavaScript代码替代,这就是 JSX的换位符 。
正如文章开头所提到的,Babel会把JSX转译成一个名为 React.createElement()
函数调用。比如下面的两段代码,起到的作用是同等的:
// JSX代码 ReactDOM.render(, document.getElementById('root') ) // JavaScript ReactDOM.render( React.createElement( "div", {id: "box"}, React.createElement( "h1", null, "title" ), React.createElement( "p", null, "paragraph" ) ), document.getElementById('root') );title
paragraph
JSX和JavaScript两段代码同样可以借助在线的Babel工具查看。
上面的示例也再次验证了,虽然JSX和JavaScript所起的效果是等效的,但相比而言,JavaScript要比JSX复杂的多。另外 React.createElement()
会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个这样的对象:
// 简化后的结构 React.createElement( "h1", null, "title" )
实际上,JSX仅仅只是 React.createElement(component, props, ...children)
函数的语法糖。如下JSX代码:
// JSX代码 Click Me
编译成JavaScript代码如下:
// JavaScript代码 React.createElement( MyButton, { color: "blue", shadowSize: 2 }, "Click Me" );
JSX中的JS
JSX接受任何混合的JavaScript。当你需要添加一些JavaScript时,只需要将它放到大括号 {}
中(前面也有简单的提到过)。例如,下面的示例就是向你展示了在JSX中怎么引用其他地方声明的常量:
const n