React和Babel的基本使用
本章将使用React构建一个非常简单的HTML页面,目的在于展示如何在运行时使JSX代码正确转换为浏览器可执行的JavaScript以得到我们想要的结果。
使用react.js
和react-dom.js
@H_404_9@
react.js
文件是创建React元素和组件的核心文件,react-dom.js
文件用来把React组件渲染为DOM,此文件依赖于react.js
文件,需在其后被引入。
<!DOCTYPE html> <html> <head> <script src="https://fb.me/react-15.2.0.js"></script> <script src="https://fb.me/react-dom-15.2.0.js"></script> </head> <body> </body> </html>
引入这两个文件后,我们就可以开始创建React元素和React组件了,也可以把组件渲染到DOM中了,以下是一个完整的示例,示例中我们创建了一个名为HelloMessage
的组件,该组件内包含一个React <div>
节点,该组件也被渲染进了DOM中,渲染位置在<div id="app"></div>
元素内。
<!DOCTYPE html> <html> <head> <script src="https://fb.me/react-15.2.0.js"></script> <script src="https://fb.me/react-dom-15.2.0.js"></script> </head> <body> <div id="app"></div> <script> var HelloMessage = React.createClass({ displayName: 'HelloMessage',render: function render() { return React.createElement('div',null,'Hello ',this.props.name); } }); ReactDOM.render(React.createElement(HelloMessage,{ name: 'John' }),document.getElementById('app')); </script> </body> </html>
React的基本使用方法就是这样,不过值得注意的是上述代码中没有使用JSX,代码因而略显复杂,下面我们将讨论如在React中使用JSX。
本节笔记
不要把HTML的
<body>
当做React渲染的根元素,记住要渲染在<body>
里一个具有id的<div>
里,这使得React有自己的独立空间,而不用担心如果其他因素如果需要操作<body>
里的子元素会影响React的使用。
使用JSX@H_404_9@
上例中的<HelloMessage>
组件是中,React使用到了React.createClass()
和React.createElement()
两个方法,这段代码就算可以直接运行在浏览器中。
使用JSX,可以极大的简化React元素的创建,JSX抽象化了React.createElement()
函数的使用,其语法风格类似于HTML语法风格。对比如下代码可以让你更好的理解这一点。
// 使用React.createElement() return React.createElement('div','Hello',this.props.name); //使用JSX return <div>Hello {this.props.name}</div>
通过Babel,JSX会把转换为使用React.createElement()
类的ES5的语句,以使得其能被现今的浏览器引擎识别。
有了Babel,其实你可以把JSX当做写在JavaScript里的HTML代码。本书后续有一章将单独讲解JSX,那时我们再详细讨论JSX的其它特性。
不过现在我们应该明白,使用React并非必须使用JSX,JSX只是一种直观的创建React nodes的方法,它是对React.createElement()
方法的抽象,通过Babel,JSX语句也可以直接在浏览器中运行了。
转换JSX
一般说来,JSX代码一般在开发阶段通过使用Babel命令行工具(Babel CLI)或者类似于webpack这样的打包工具处理。不过我们也可以像使用使用jQuery那样,引用脚本文件在浏览器中处理JSX代码,这是最方便的方法,我们在此先这样做。
不过遗憾的是新版的Babel(Babel6以后)不再提供这种直接引用的文件,因此需要使用老版本的Babel(5.8.23)来在浏览器中处理JSX文件。
使用browser.js(Babel5.8.23)
在浏览器中转换JSX
下例还是上面已经见过的那个<HelloMessage>
组件,这次我在其中加入了brower.js
的引用,用以转换JSX代码,注意引用的<script>
的type为type="text/babel"
.
<!DOCTYPE html> <html> <head> <script src="https://fb.me/react-15.2.0.js"></script> <script src="https://fb.me/react-dom-15.2.0.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script> </head> <body> <div id="app"></div> <script type="text/babel"> var HelloMessage = React.createClass({ render: function() { return <div>Hello {this.props.name}</div>; } }); ReactDOM.render(<HelloMessage name="John" />,document.getElementById('app')); </script> </body> </html>
在运行时引用
babel.js
虽然容易使用而且还很方便,不过并不是一种好的方案,因为需要转换,所以更加耗时,这一缺点在产品阶段显得更加明显。类似于JSFiddle
这样的工具,在线转换React用的就是这种方法。
本节笔记
Babel是React团队选择的在使用React过程中转换ES*和JSX为ES5语句的工具,可以从Babel handbook了解Babel详细的用法。
-
使用JSX有以下好处
容易理解和修改,对CSS开发者友好;
在JavaScript中使用HTML可以避免使用模板,JSX并非一种模板,它其实是用来描述UI组件树的一种JavaScript语句拓展。
使用JSX,使你更容易找到可能出错的地方;
JSX促进inline styles的发展,这可能是一件很棒的事情;
JSX Gotchas能让你更加了解JSX;
JSX被列为了ECMAScript用以拓展类XML语句的草案,所以放心使用吧;
使用ES6和RS*@H_404_9@
Babel并非React的一部分,实际上,Babel的主要用途并非一个JSX语句转换器。Babel主要是一个JavaScript转换器,它可以转换各种ES*代码为浏览器可识别的ES代码。就目前来说,Babel主要会转换ES6和ES7语句为ES5语句,转换JSX看起来倒像是其的一个附加功能。
有了Babel,我们可以放心的在React中使用最新的ES语句了。
以下是使用ES6语句书写的<HelloMessage>
组件,不用担心它的兼容性,Babel都帮我们做好了。
<!DOCTYPE html> <html> <head> <script src="https://fb.me/react-15.2.0.js"></script> <script src="https://fb.me/react-dom-15.2.0.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script> </head> <body> <div id="app"></div> <script type="text/babel"> class HelloMessage extends React.Component { //notice use of React.Component render(){ return <div>Hello {this.props.name}</div>; } }; ReactDOM.render(<HelloMessage name="John" />,document.getElementById('app')); /*** ES5写法 ***/ /*var HelloMessage = React.createClass({ render: function() { return <div>Hello {this.props.name}</div>; } }); ReactDOM.render(<HelloMessage name="John" />,document.getElementById('app'));*/ </script> </body> </html>
Babel会转换如下代码
class HelloMessage extends React.Component { render(){ return <div>Hello {this.props.name}</div>; } }; ReactDOM.render(<HelloMessage name="John" />,document.getElementById('app'));
转换后的结果如下
"use strict"; var _createClass = (function () { function defineProperties(target,props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target,descriptor.key,descriptor); } } return function (Constructor,protoProps,staticProps) { if (protoProps) defineProperties(Constructor.prototype,protoProps); if (staticProps) defineProperties(Constructor,staticProps); return Constructor; }; })(); var _get = function get(_x,_x2,_x3) { var _again = true; _function: while (_again) { var object = _x,property = _x2,receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object,property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; function _classCallCheck(instance,Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _inherits(subClass,superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function,not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype,{ constructor: { value: subClass,enumerable: false,writable: true,configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass,superClass) : subClass.__proto__ = superClass; } var HelloMessage = (function (_React$Component) { _inherits(HelloMessage,_React$Component); function HelloMessage() { _classCallCheck(this,HelloMessage); _get(Object.getPrototypeOf(HelloMessage.prototype),"constructor",this).apply(this,arguments); } _createClass(HelloMessage,[{ key: "render",value: function render() { return React.createElement( "div","Hello ",this.props.name ); } }]); return HelloMessage; })(React.Component); ; ReactDOM.render(React.createElement(HelloMessage,{ name: "John" }),document.getElementById('app'));
大多数ES6的特性都能被Babel5.8.23安全的转换(少数会有警报)。
本节笔记
阅读Babel handbook可获取更多关于Babel的信息。
在JSFiddle中练习使用React@H_404_9@
本文谈论到的基本设置在JSFiddle中已经实现,JSFiddle正是引用了react.js
、react-dom.js
和brower.js
,这使得我们可以直接在该网站上练习使用React。以下是一个内嵌在网页中的JSFiddle,内容还是我们一直提起的HelloMessage
组件,点击Result可以查看渲染结果。
JSFiddle为我们提供一个较好的React学习过程中的场所,多多练习吧,同志们。