React入门 (1)—使用指南(包括ES5和ES6对比)
前言
本篇会简明扼要的介绍一下React的使用方法。代码会用JSX+ES5和JSX+ES6两种方式实现。
React简介
React来自Facebook,于2013年开源。至今不断修改完善,现在已经到达了版本0.14.2。可以注意到版本还没有到1.0, 普遍应用到大部分产品中还需要一定的时间。2015年3月份,FaceBook发布了React Native,一个用react来构建native app的框架。
步入正题,React是一个javascript的类库,用于构建用户界面。
三个特点
JUST THE UI
不同于Angularjs框架,React不属于MVC框架,它可以算是MVC里面的V层,所以相对来说入门也简单一下(只指入门,深度研究的话也不简单)。VIRTUAL DOM——虚拟DOM
虚拟dom其实是轻量的js对象,只保留了原生dom的一些常用的属性和方法。- 自定义标签
学习React需要有一种全新的思路去看待view层的构建。除了使用html原生的标签,开发者还可以自定义标签(即虚拟DOM,最终给浏览器渲染的时候会解析成原生dom),自然代码解耦的效果会很明显,也更易读。 - 性能提升
在大家优化代码性能的时候,一定会关注有没有多余的dom操作,这是因为dom相关的操作耗时比较长。就算是创建一个空标签,也许要初始化它的各种默认属性和事件。
React渲染页面并不直接操作dom,而是先通过diff算法比较前后虚拟dom的差异。这最大程度的简化dom操作,大大提高了性能。由于只是局部更新dom,所以只是局部刷新。
换而言之,虚拟dom的出现,是因为目前js的性能比DOM渲染的性能要好,所以可以用更多的js操作换取更少的dom操作。也不排除如果将来有一天dom的性能和js差不多的时候,虚拟dom也许就没那么大的意义了。
- 自定义标签
DATA FLOW
React是单向响应的数据流。
React相关知识简介
jsx
一种特殊的js语法,可以在js代码中直接使用html标签。是个语法糖,提高编写代码效率。
要注意不能在标签的中间添加注释,因为最终还是要翻译成原生js,标签中添加注释相当于在一行代码还没完的时候就添加注释。
在jsx中,变量用花括号包围起来,花括号内的语句将以js代码的方式解析。
例如:
// 用纯js在react中创建a标签
var newDom=<React.createElement('a', {href: 'https://facebook.github.io/react/'}, 'Hello!');
// 用jsx在react中创建a标签
var newDom=<a href="https://facebook.github.io/react/">Hello!</a>;
要让浏览器认识这种新的语法,就需要下面介绍的babel了。
babel
是一个javascript代码转换器,在这里我们可以用于jsx转换为原生js,es6转换为es5(大部分都能转换)。当然它的功能不只这些,有兴趣的可以去babel官网看看。它还有个线上的转换器,代码比较简单的时候用这个排查问题或练习es6很方便。
介绍两种常用的使用方式:
- 一种是浏览器来编译,因为实时编译会很慢,所以适合代码量比较小的。只需在html中引用:
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
- 一种是本地使用。通过npm安装,在webpack中配置:
//在webpack.config.js文件中配置
module.exports = {
module: {
loaders: [{
test: /\.jsx?$/,
loader: 'babel'
}]
}
}
可以在本地编译好代码后,再将编译后的代码给html引用,提高性能,适合大项目。
webpack
一个模块打包工具,它把不同的、相互依赖的静态资源都视作模块,并且打包成我们想要的静态资源。
另外可以方便的配置多种预处理器,如babel。
使用webpack,让代码组织更清晰,一个文件就是一个模块。
ES6
ES6,也叫ECMAScript2015(以下统称ES6),是ECMAScript标准的最新版本。详细可见ES6的特性简述(译+部分解析)
搭建简单的运行环境
- 方式一:直接引入react、reactdom、babel的库。
因为这种方式是浏览器负责即时编译的,所以可想而知项目大了得时候解析速度会很慢,不建议使用。但是我们只是学习react语法嘛,当然要搭的环境越简单越好。
这种方式就是官网给出的实例所使用的方式。注意写jsx的的js块的type="text/babel",这样才能被浏览器识别并用babel编译。
以下是本章要用到的代码框架(一个helloword的demo) :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>demo</title>
</head>
<body>
<div id='example'></div>
<script src="./build/react.js"></script>
<script src="./build/react-dom.js"></script>
<script src="./build/browser.min.js"></script>
<script type="text/babel">
// react代码写到这里
ReactDOM.render(<h1>hello word!</h1>,document.getElementById('example'));
</script>
</body>
</html>
- 方式二:使用npm + webpack
篇幅限制,下篇说,欢迎看第二篇。
学会react的基本语法
一般从定义到使用组件的流程是:定义组件creatClass,实现render方法->将组件渲染到页面ReactDOM.render()。
创建ReactElement
ReactElement对象可以看成是虚拟DOM树。它既是渲染组件ReactDOM.render(root,container)的第一个参数,又是创建组件React.createClass中render方法的返回值。记住ReactElement是唯一父节点的’dom树‘就好。
- react原生实现
React.createElement(
string/ReactClass type, //type组件类型可以是内置的标签,如div;也可以是由React.createClass(object specification)创建的虚拟组件
[object props], // 标签属性,数组
[children ...],// 标签的innerHtml
)//返回类型是ReactElement
var newDom=React.createElement('a', {href: 'https://facebook.github.io/react/'}, 'Hello!');
- jsx实现
<a href=''>Hello</a>
把组件渲染到浏览器中
react-dom模块中的方法。
ReactDom.render(root, container);
root为ReactElement类型,表示root替换container中的元素。注意是替换不是追加,所以有些情况父元素应该设置为空。
- react原生
var content=React.createElement('h1',{},'hello');
ReactDOM.render(content,document.getElementById('example'));
- jsx
ReactDOM.render(<h1>hello word!</h1>,document.getElementById('example'));
创建组件
组件是一个自定义的js对象,在es5中使用React.createClass();在es6中必须继承React.component。
其中有个特殊的render方法,返回ReactElement对象。该方法会在我们使用JSX语法的标签时被调用,因此我们在渲染组件时第一个参数可以使用自定义标签或者createElement。
如:ReactDOM.render(<MyElement />,document.getElementById('example'))
- es5
var NewDom = React.createClass({//类名一定要大写开头
render: function() {
return (
<ol>
{
React.Children.map(this.props.children, function (child) {
//获得元素的子元素
console.info(this);
console.info('child:'+child);
return <li>{child}</li>;//变量用花括号标识
})//因为有多个子元素,所以返回的是数组。按照JSX变量是数组来解析。
}
</ol>
);
}
});
ReactDOM.render(
<NewDom>
<span>lala</span>
<span>ass</span>
</NewDom>,
document.getElementById('example')
);
- es6
class NewDom extends React.Component{
render() {//开头花括号一定要和小括号隔一个空格,否则识别不出来
return <ol>//标签开头一定要和return一行
{
React.Children.map(this.props.children, function (child) {
return <li>{child}</li>;
})
}
</ol>;
}
}
ReactDOM.render(
<NewDom>
<span>lala</span>
<span>ass</span>
</NewDom>,
document.getElementById('example')
);
组件的属性props
一个js对象,对应于dom的属性。
- 原生属性
某些html的属性名因为正好是js得保留字,所以需要重新命名。- class
因为js中class为保留字,所以要写成className。
<a className="center"></a>
- style
style属性接受由css属性构成的js对象。对于jsx来说第一是变量,第二是对象,因此要两个花括号,key值用驼峰命名法转化了,value值用引号括起来
<a style={{backgroundImage: 'url(' + imgUrl + ')',font:'12px'}}></a>
- class
- 新增属性
this.props.children 表示组件的所有子节点,上一小节的示范代码中有介绍 - 传递属性值
在ReactDOM.Render第一个参数中直接写入带属性的标签即可:<a newProp="propValue"></a>
。这样就可以在this.props['newProp']中读取值 - 设置默认属性
- 在ES6中为属性:defaultProps(可以标识static定义在class内,也可以定义在class外)
- 在ES5中为方法:getDefaultProps: function(){return {name:value}};
- 属性的读取
this.props['propName']获得属性 - 新增功能:属性校验器propTypes
见代码示例 - 代码示范
- es5
var NewDom = React.createClass({//类名一定要大写开头
getDefaultProps: function() {//设置默认属性
return {title:'133'};
},
propTypes: {
title:React.PropTypes.string,
},//属性校验器,表示必须是string
render: function() {
return <div>{this.props.title}</div>;//变量用花括号标识
}
});
- es6
class NewDom extends React.Component{
//不能再组件定义的时候定义一个属性
render() {
return <div >1{this.props.title}</div>;
}//开头花括号一定要和小括号隔一个空格,否则识别不出来
}
//es6 这两个属性不能写在class内。
NewDom.propTypes={//属性校验器,表示改属性必须是bool,否则报错
title: React.PropTypes.bool,
}
NewDom.defaultProps={title:'133'};//设置默认属性
组件的状态state
一个js对象,存储着组件当前的状态以及其值的集合。
个人觉得这也是react的创新点之一,可以把组件看成一个“状态机”. 根据不同的status有不同的UI展示。只要使用setState改变状态值,根据diff算法算出来有差以后,就会执行ReactDom的render方法,重新渲染页面。
这避免了开发者直接操作dom对象已达到重新渲染页面。开发者只需要关注state这个中间人,控制它就可以控制页面刷新。第二篇中评论框的渲染就是使用的state来控制。
是不是感觉和props有些类似?一般区分两个的原则是,可变的放在state中,不可变的放在props中。
- 初始化
- es5
class *** extends React.Component{
getInitialState: function() {
return {liked: false};
}
}
- es6
class *** extends React.Component{
constructor(props) {
super(props);
this.state = {liked: false};
}
}
- 修改值
es5和es6中使用方法相同。
this.setState(新的state对象);
- 读取值
其实就是读取一个js对象。
事件
事件名
和属性名类似,到了react中,事件名也成了驼峰命名法,比如onclick变为了onClick.事件定义
一定要注意es6中元素如何使用自定义事件。见代码。- es5
var NewDom = React.createClass({//类名一定要大写开头
btnClick:function(ele){
console.info(ele);
console.info(this.refs.tex);
},
render: function() {
return <div >
<input type="text" ref="tex" />
<input type="button" onClick={this.btnClick} value='click me' />
</div>;//变量用花括号标识
}
});
- es6
class NewDom extends React.Component{
btnClick(){
console.info(this);//this为该组件类
console.info(this.refs.tex);//this.refs.tex为组件里面索引为tex的
}
render() {
return <div >
<input type="text" ref="tex" />
<input type="button" onClick={this.btnClick.bind(this)} value='click me' />
</div>;//注意bind后面的this
}
}
- 事件target
下面是一个事件对应要执行的函数的定义:
handleChange: function(event) {
this.setState({value: event.target.value});//event.target.value元素的值
}
每个控件取值不一样,value是指input控件,下拉框为selected,radiobutton为checked。a标签是innerHtml。可以自己通过console.info(e.target) 调试出自己想要的那个字段
ES6的坑
- 类名(组件名)一定要用大写开头,否则自定义的组件无法编译,识别不出来。
- 类中定义render函数要注意两点,见代码注释。
render() {//开头花括号一定要和小括号隔一个空格,否则识别不出来
return <ol>//标签前一半一定要和return一行
{
React.Children.map(this.props.children, function (child) {
return <li>{child}</li>;
})
}
</ol>;
}
- 在class中使用class的变量或者方法,一定要加个this。如this.handlerclick。
- es6 绑定事件需要
onClick={this.func1.bind(this)}
。
这样func1和bind里面的参数‘this’的作用域才绑定到了一起(注意es5是不需要这个bind(this)的),func1中如果有this.name这类语句,相当于是使用参数‘this’里面的变量值;或者使用箭头函数func1= (e)=> {函数体}
小结
经过这番简单的练习后,如果还想看看做一个项目中如何使用react参见下章,一个模仿微博展示的demo(编写ing)。
本文没有对react作深入的研究。通过学习react的使用方法可以看到,react入门的话相对于其他框架还是比较简单的,代码逻辑也很清晰,好维护也好使用。重要的是,需要使用者把从前直接对dom操作的思维方式转换过来,相信会爱上它的。
ps: react 还在发展期,学习的话建议英语好的直接看官方文档,可以少走一些弯路。
React入门 (1)—使用指南(包括ES5和ES6对比)的更多相关文章
- ES5与ES6对比
ES5与ES6对比 1. 模块引用 1.在ES5里,引入React包基本通过require进行,代码类似这样: // ES5 var React = require('react'); var { C ...
- JavaScript面向对象轻松入门之概述(demo by ES5、ES6、TypeScript)
写在前面的话 这是一个JavaScript面向对象系列的文章,本篇文章主要讲概述,介绍面向对象,后面计划还会有5篇文章,讲抽象.封装.继承.多态,最后再来一个综合. 说实话,写JavaScript面向 ...
- JavaScript面向对象轻松入门之封装(demo by ES5、ES6、TypeScript)
本章默认大家已经看过作者的前一篇文章 <JavaScript面向对象轻松入门之抽象> 为什么要封装? 封装(Encapsulation)就是把对象的内部属性和方法隐藏起来,外部代码访问该对 ...
- JavaScript面向对象轻松入门之多态(demo by ES5、ES6、TypeScript)
多态(Polymorphism)按字面的意思就是"多种状态",同样的行为(方法)在不同对象上有不同的状态. 在OOP中很多地方都要用到多态的特性,比如同样是点击鼠标右键,点击快捷方 ...
- JavaScript面向对象轻松入门之抽象(demo by ES5、ES6、TypeScript)
抽象的概念 狭义的抽象,也就是代码里的抽象,就是把一些相关联的业务逻辑分离成属性和方法(行为),这些属性和方法就可以构成一个对象. 这种抽象是为了把难以理解的代码归纳成与现实世界关联的概念,比如小狗这 ...
- JavaScript面向对象轻松入门之继承(demo by ES5、ES6)
继承是面向对象很重要的一个概念,分为接口继承和实现继承,接口继承即为继承某个对象的方法,实现继承即为继承某个对象的属性.JavvaScript通过原型链来实现接口继承.call()或apply()来实 ...
- React入门 (2)—实现微博展示列表
前言 如果从来不了解React先看前篇React入门 (1)-使用指南(包括ES5和ES6对比). 本文为了能将前篇学到的react知识学以致用,做了一个类似微博展示列表的demo.使用的是ES6+R ...
- Weex入门与进阶指南
Weex入门与进阶指南 标签: WeexiOSNative 2016-07-08 18:22 59586人阅读 评论(8) 收藏 举报 本文章已收录于: iOS知识库 分类: iOS(87) 职 ...
- es6 Object.assign ECMAScript 6 笔记(六) ECMAScript 6 笔记(一) react入门——慕课网笔记 jquery中动态新增的元素节点无法触发事件解决办法 响应式图像 弹窗细节 微信浏览器——返回操作 Float 的那些事 Flex布局 HTML5 data-* 自定义属性 参数传递的四种形式
es6 Object.assign 目录 一.基本用法 二.用途 1. 为对象添加属性 2. 为对象添加方法 3. 克隆对象 4. 合并多个对象 5. 为属性指定默认值 三.浏览器支持 ES6 O ...
随机推荐
- 在Asp.net MVC使用jqGrid--代码少点再少点
本示例显示了如何动态生成前端jqGrid代码,一般情况仅一行代码: <%=Html.jqGrid<TestModel>(@"#jqT", "Test&q ...
- EF深入系列--Code First
首先是创建DbContext,有两种途径 ①手动编写DbContext代码,同时还要记得去配置文件中添加connectionStrings public class BooksContext : Db ...
- C#调用SQL Server参数过程传参
-SQL SERVER生成测试环境: Create database Test; go USE [Test] GO if OBJECT_ID('Tab2','U') is not null drop ...
- ASP.NET Web API 简介
ASP.NET MVC 4 包含了 ASP.NET Web API, 这是一个创建可以连接包括浏览器.移动设备等多种客户端的 Http 服务的新框架, ASP.NET Web API 也是构建 RES ...
- SQL Server 2008 R2——T-SQL 存储过程 返回表
==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...
- YUV420查表法高效、无失真的转换为RGB32格式
YUV格式有两大类:planar和packed.planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V,这里所讲述的就是这中存储格式的:packed的YUV ...
- ZooKeeper日志与快照文件简单分析
有用过Zookeeper的都知道zoo.cfg配置文件中有dataDir配置项用于存储数据,不过可能有些人不太清楚这个目录具体存储的是那些数据,默认情况下这个目录是用于存储Log(事务日志)与Snap ...
- 003.同时Ping多个IP(select实现IO复用,信号计时),ping程序升级版
写这个的目的主要是为了以后的方便: 1.信号计时函数的使用 2.ip头的构建和icmp头的构建 3.selec函数t的用法 代码实现: /src/ping.h /* * ping.h * * Crea ...
- 必须知道的八大种排序算法【java实现】(三) 归并排序算法、堆排序算法详解
一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并 ...
- IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇)
IO - 同步,异步,阻塞,非阻塞 (亡羊补牢篇) 当你发现自己最受欢迎的一篇blog其实大错特错时,这绝对不是一件让人愉悦的事. <IO - 同步,异步,阻塞,非阻塞 >是我在开始学习e ...