JSX(JavaScriptXML)提供了一种在JavaScript中编写声明式的XML的方法,使用JSX可以提高组件的可读性,React允许做简单的JSX语法转化。
JSX像是在JavaScript代码里直接写XML的语法,每一个XML标签都会被JSX转换工具转换成纯JavaScript代码,React 官方推荐使用JSX,这个看个人习惯, 如果你喜欢纯JavaScript代码也是可以的,只是使用JSX会给我们带来如下好处:
- 是原生的JavaScript;
- 程序结构更容易被直观化;
- 提供更加语义化且易懂的标签;
- 抽象了React Element的创建过程;
- 允许使用熟悉的语法来定义HTML元素树;
- 可以随时掌控HTML标签以及生成这些标签的代码;
简单的理解组件就是对数据和方法的简单封装,目的就是模块化功能。在React当中组件是用来分离关注点的,而不是被当做模板或处理显示逻辑的,在使用React开发应用过程中,往往HTML标签以及生成这些标签的代码之间存在着内在的紧密联系,其实这一坨代码就可以理解为是一个组件。
接下来看一个简单的DEMO,定义我们的第一个组件,按照以往的游戏规则,我们就给他起一个文雅又响亮的名字——“HelloWorld”(React的安装包可以到官网去下载):
<!DOCTYPE html><html> <head> <title>Hello React</title> <!--React核心库--> <script src="build/react.js"></script> <!--react-dom.js提供与DOM相关功能--> <script src="build/react-dom.js"></script> <!--browser.js将 JSX 语法转为 JavaScript 语法--> <script src="build/browser.min.js">/script> </head> <body> <HelloWorld>Hello World!</HelloWorld> <!--为了把 JSX 转成标准的 JavaScript,我们用 `<script type="text/babel">` 标签,然后通过Babel转换成在浏览器中真正执行的内容--> <script type="text/babel"> // 定义组件HelloWorld var HelloWorld = React.createClass({ render : function(){ return ( <div> <h1>this.props.children</h1> </div> ); } }) </script> </body></html>
关于上例中的几点说明:
- React中组件名必须以大写字母开头;
- React中的组件只能包含一个顶层标签,否则会报错;
- JSX将两个花括号之间的内容{...}渲染为动态值,花括号指明了一个JavaScript上下文环境,它会将其中内容进行求值,然后渲染为标签中的若干节点;
- this.props.children是组件的特殊属性,保存了开始标签与结束标签之间的所有子节点,上例中this.props.children = ["Hello World!"];
上述代码如果不使用JSX语法,写法如下:
...// 定义组件HelloWorldvar HelloWorld = React.createClass({displayName:"HelloWorld ", render : function(){ return ( React.createElement("div",null); React.createElement("h2",null,this.props.children); ); }})...
不管使不使用JSX,HelloWorld组件最终的页面渲染结果都是一样的,如下所示:
<div> <h1>Hello World!</h1></div>
“这个规范(JSX)并不尝试去遵循任何XML或HTML规范。JSX是作为一种ECMAScript特性来设计的,至于大家觉得JSX像XML这一事实,那仅仅是因为大家比较熟悉XML。”——以上内容摘自http://facebook.github.io/jsx/
由此我们可以看出JSX仅仅是像HTML而已,接下来看下他们之间的关键区别。
在HTML中我们往往通过内联的方式设置标签的属性,JSX在支持这种方式的基础上,还支持动态的设置标签的属性,具体实现形式如同我们上个DEMO中的{...},我们可以将属性值定义为JS变量或者是函数。如下所示:
<!--在HTML中标签属性示例--><div id="demo" class="myStyle"></div><!--在JSX中标签属性示例-->var demoId = this.props.id;var demoClass = "myStyle";function getName(){ ...}<div id={demoId} name={this.getName()} className={demoClass}></div>
在React渲染组件的过程中,我们上面定义的变量和函数会被求值,最终生成的DOM结构会反映出这个新的状态。
下列属性只在JSX中存在:
- key:可选的唯一标示符,用来唯一的标识一个组件;
- ref :允许父组件在render之外保持对子组件的一个引用;
- dangerouslySetInnerHtml:提供插入纯 HTML 字符串的功能,主要为了能和生成 DOM 字符串的库整合。
接下来详细看一下这几个特殊属性的作用。
键(key)在程序运行过程中,由于用户与应用间的交互等原因,一个组件在组件树中的位置很有可能发生改变,最常见的例子就是某列表记录的增、删操作。当然这种情形下组件可能并不需要被销毁并重新创建。
通过给组件设置一个唯一的标识,且保证它在一个渲染周期中保持一致,这样React就能智能的决定该重用哪一个组件,或者销毁并重新创建一个组件,避免不必要的重新渲染,得到性能的提升。
引用(ref)在JSX中可以通过在属性中设置期望的引用名来定义一个引用。
var App = React.createClass({ getInitialState: function() { return {userInput: ''}; }, handleChange: function(e) { this.setState({userInput: e.target.value}); }, clearAndFocusInput: function() { // 清空输入框 this.setState({userInput: ''}, function() { // 这段代码会在组件重新渲染后执行,使输入框重获焦点 this.refs.theInput.getDOMNode().focus(); }); }, render: function() { return ( <div> <div onClick={this.clearAndFocusInput}> 点我!点我!!点我!!! </div> <input ref="theInput" value={this.state.userInput} onChange={this.handleChange} /> </div> ); } });
然后我们就可以在组件中的任何地方使用这个引用了。通过引用获取到的这个对象叫做支持实例。他并不是一个真的DOM,而是React在需要时创建的一个描述对象。你可以通过this.refs.theInput.getDomNode()来访问真实的DOM节点。
设置原始的HTMLdangerouslySetInnerHTML—— 顾名思义,从属性名当中就能看出来,以此来警告它的值( 一个对象而不是字符串 )应该被用来表明净化后的数据。在彻底的理解安全问题后果并正确地净化数据之后,生成只包含唯一 key __html 的对象,并且对象的值是净化后的数据,示例如下:
function createMarkup() { return {__html: 'First · Second'}; };<div dangerouslySetInnerHTML={createMarkup()} />
这么做的意义在于,当你不是有意地使用
时候,它并不会被渲染,因为 getUsername() 返回的格式是 字符串 而不是一个{__html: ''} 对象。{__html:...} 背后的目的是表明它会被当成 "type/taint" 类型处理。 这种包裹对象,可以通过方法调用返回净化后的数据,随后这种标记过的数据可以被传递给dangerouslySetInnerHTML。 基于这种原因,我们不推荐写这种形式的代码:这个功能主要被用来与 DOM 字符串操作类库一起使用,所以提供的 HTML 必须要格式清晰(例如:传递 XML 校验 )
由于JSX本质上就是JavaScript,因此也支持JavaScript的注释方式,在JSX中可以用以下两种方式添加注释:
- 当做一个元素的子节点;
- 内联在元素的属性中;
示例如下:
// 作为一个元素的子节点<div>{/*多行注释*/}<h1>This is a h1 tag.</h1></div>// 内联在元素的属性中<div><h1/* * 多行注释 */ > 多行注释 </h1></div><div><h1//单行注释 >单行注释</h1></div>
由于JSX会转化为JavaScript函数,所以有些关键词我们不可以使用,比如for和class。
这两个属性分别可以用htmlFor和className替换,参考如下示例:
<label htmlFor="name" ...><input calssName={classes} ...>
React把所有的内联样式都规范化为驼峰形式,同样类似于JavaScript中DOM的style属性,要给组件添加自定义属性,如下:
var styles = { width:100px; height:100px;}React.renderComponent({<div style={styles}>...</div>,node})
【1】《React引领未来的用户界面开发框架》【2】 React中文官网