React躬行记(2)——JSX

  JSX既不是字符串,也不是HTML,而是一种相似XML,用于描述用户界面的JavaScript扩展语法,以下代码所示。在使用JSX时,为了不自动插入分号时出现问题,推荐在其最外层用圆括号包裹,而且必须用一个元素包裹(例以下面的<div>元素)其它元素或文本,全部的元素还必须得闭合。html

(<div>
  <input type="text" text={getName()} />
  <button className="btn">搜索</button>
</div>)

  JSX为视图和数据架起了一座沟通的桥梁,它看起来与模板语言相似,但没有创造新的模板语法,由于JSX最终会被编译成普通的JavaScript对象,因此可以直接使用JavaScript语法。react

1、元素

  JSX中的元素称为React元素,分为两种类型:DOM元素和组件元素,前者对应原生的HTML元素,标签的首字母要小写;后者对应自定义元素,标签的首字母要大写,以下所示。算法

<button>提交</button>;            //DOM元素
<Btn>自定义按钮</Btn>;             //组件元素

1)React.createElement()react-native

  不管是DOM元素仍是组件元素,最终都会经过Babel编译器将它们转换成React.createElement()方法的调用,例以下面的<button>元素。浏览器

<button className="btn">搜索</button>
//编译成
React.createElement(button, { className: "btn" }, "搜索");

  React.createElement()能接收3个参数(以下所示),其中type是元素类型,也就是它的名称;props是一个由元素属性组成的对象;children是它的子元素(即内容),能够是文本也能够是其它元素。babel

React.createElement(type, [props], [...children])

  方法的返回值是一个元素对象,简化过的对象以下所示。dom

{
  type: "button",
  props: {
    className: "btn",
    children: "搜索"
  }
}

  为了不在多人协做时出现相同名称的元素,能够为元素添加命名空间,例如调用UI模块中的Btn元素,能够像下面这么写。函数

const UI = {
  Btn: function(props) {
    return <button className={props.className}>{props.children}</button>;
  }
}
<UI.Btn className="btn">搜索</UI.Btn>

2)注释性能

  JSX中的注释须要像下面这样,用一对花括号、斜杠和星号包裹。spa

{/* 表单中的提交按钮 */}
<button>提交</button>

3)表达式

  在JSX的任意位置都能插入表达式,但必须用花括号包裹住才能有效,例如像下面这样调用getName()函数。注意,在JSX中不能插入语句。

function getName() {
  return "strick";
}
<div>{getName()}</div>

  因为JSX自己就是一种表达式,所以它能够做为函数的参数、返回值或变量的值,以下所示。

if (true) {
  let fragment = <div>{getName()}</div>;
}

  在JSX中传入的值都会自动被HTML转义,这样能够防止XSS攻击,例如输入“<p></p>”,输出“&lt;p&gt;&lt;/p&gt;”,以下所示。

//&lt;p&gt;&lt;/p&gt;
<div>{"<p></p>"}</div>

  若是要输出不转义的值,那么能够用React提供的dangerouslySetInnerHTML属性,以下代码所示。它的值是一个包含__html属性的对象,其做用至关于调用DOM元素的innerHTML属性。

<div dangerouslySetInnerHTML={{__html: "<p></p>"}}></div>

4)内容

  当元素的内容是字符串时,JSX会移除字符串中的空行,其内部的换行会被替换成一个空格,下面的两个元素是等价的。

<p>freedom strick</p>
<p>
  freedom
          
  strick
</p>

  当元素的内容是false、null、undefined或true时,它们都不会被渲染到DOM结构中,所以下面的五个元素是等价的。

<p></p>
<p>{false}</p>
<p>{null}</p>
<p>{undefined}</p>
<p>{true}</p>

5)渲染

  若是要将React元素渲染到页面的DOM结构中,能够调用ReactDOM.render()方法,此方法接收3个参数,以下所示。

ReactDOM.render(element, container[, callback])

  element是要渲染的元素;container是页面中的一个节点,在此处起到容器的做用,element会被渲染到container中;callback是可选的回调函数,会在组件被渲染或更新以后触发。此方法的使用可参考下面的示例。

<div id="container">freedom</div>
<script type="text/babel">
  ReactDOM.render(
    <p>strick</p>, 
    document.getElementById("container") 
  );
</script>

  当第一次调用ReactDOM.render()方法时,容器内部的元素会被所有替换掉,也就是执行上面的代码获得的结果以下所示,原先的字符串“freedom”被替换成了<p>元素。

<div id="container">
  <p>strick</p>
</div>

2、属性

  React对元素属性进行了一次封装,不只规范了属性的命名,还完善了浏览器的兼容性。在JSX中,DOM元素的属性对应标准的DOM属性和特性;而组件元素的属性都是无对应关系的自定义属性。除了以“data-”和“aria-”为前缀的元素属性要用小写命名以外,其他的都得遵循小驼峰命名法,例如maxlength变成maxLength、onclick变成onClick等。还有两个比较特殊的属性:class和for,因为它们是JavaScript的关键字,所以须要变成className和htmlFor后才能使用。

1)默认值

  属性的默认值是true,下面的两个元素是等价的,页面上的显示如图1所示。

<input type="text" value />
<input type="text" value={true} />

图 1   带默认值的文本框

  在标准的DOM中,诸如checked、disabled等布尔属性,它们的值要么为空要么为对应的关键字,例如“checked”、“disabled”;而JSX中的布尔属性,它们的值只能是true或false。

2)字符串和表达式

  当属性的值是字符串时,其值须要用双引号包裹;当属性的值是表达式时,其值须要用花括号包裹,以下所示。

<input type="text" value="3" />
<input type="text" value={1 + 2} />

3)扩展属性

  若是存在一个由元素属性组成的属性对象,那么就能利用ES6新增的扩展运算符,把属性对象展开并传递给元素,以下所示。

var props = { type: "text", value: "1" };
<input {...props} />
//至关于
<input type="text" value="1" />

  相比直接在元素上设置属性,这种方式操做起来更加灵活。

3、虚拟DOM

  HTML文档能被抽象成一棵由多种类型的节点构成的DOM树,而每次对DOM节点执行增删改查等操做,每每会触发很是消耗性能的重绘和重排。为了解决这个性能瓶颈,React引入了虚拟DOM。虚拟DOM(Virtual DOM)是构建在真实DOM之上的一层抽象,它将DOM元素映射成内存中的JavaScript对象(即经过React.createElement()获得的React元素),造成一棵JavaScript对象树。

  在React中,将虚拟DOM转换成真实DOM的过程叫作调和(Reconciliation),而diff算法是保证调和高效的关键,由于diff算法会找出新旧虚拟DOM之间的差别部分,随后只更新真实DOM中须要变化的节点,而不是将整棵DOM树从新渲染一遍。通过虚拟DOM的隔离,开发人员已经不用再直接与页面上的真实DOM打交道了,如图2所示。

图 2   新的开发模式

  虚拟DOM还有一大亮点,那就是将它与其余渲染器配合可以集成到指定的终端,即将React元素映射成对应的原生控件,前文所描述的是用react-dom在Web端渲染,还可使用react-native在手机端(Android或iOS)渲染。

相关文章
相关标签/搜索