一个用来构建用户界面的Javascript库,据说是颠覆式的前端UI开发框架,听上去如此的高大上,作为一名长期在前端奋战的攻城狮,定要来一睹React的风采。
首先对React作简单介绍:
####1、 由来: 是Facebook推出的一个用来构建用户界面的Javascript库。 ####2、 特征:
1》并非是一个完整的MVC框架,可以认为是MVC中的View 2》采用单向数据流,易追踪数据 3》将Html/JavaScript结合起来构建组件,组件将状态和结果一一对应 起来,实现模块化开发,形成直观的声明式编程方式 4》优势之一为高性能的虚拟DOM,从而屏蔽掉人工DOM操作
现在,对于React编程是不是跃跃欲试了呢,下面介绍下如何开始上手来写代码
搭建简单的React环境:
下载初学者教程包Starter Kit http://reactjs.cn/react/docs/getting-started.html
build
目录下新建test.html
,此时即可编写简单的React代码例1:
<html>
<head>
<meta charset="utf-8">
<title>demo</title>
</head>
<body>
<script src="react.js"></script>
<script src="JSXTransformer.js"></script>
//渲染HTML标签
<script type="text/jsx">
var div = React.createElement('div',null,"hello");
React.render(div,document.body);
</script>
</body>
</html>
注意:上述中script
的type
应为“text/jsx”
使用JSX
语法来实现上边的功能,只需将上边的var div
该行代码修改为下边即可:
例2:
<html>
<head>
<meta charset="utf-8">
<title>demo</title>
</head>
<body>
<script src="react.js"></script>
<script src="JSXTransformer.js"></script>
<script type="text/jsx">
//使用JSX语法渲染React组件,组件名首字母大写,若小写默认会去找DOM标签,则找不到
var Hello = React.createClass({
render:function(){
return (
<div>hello world</div>
);
}
});
//引用组件时遵循标签闭合原则
React.render(<Hello />,document.body);
</script>
</body>
</html>
看到这小伙伴是不是惊呆了!!js跟html又在一起了啊!曾花多年时间终于将构建界面的html和实现逻辑的js相互分离开,就这样被打破了。
个人认为,之前的MVC结构的html模板中的内容严重依赖于数据逻辑和DOM结构,使得html和js还是有很大程度的耦合,且逻辑和模板是分文件存放,
使得实际编写代码时两文件得来回对照,给编写造成很大不便。
因此再将js跟html整合在一起也无可厚非,说不定会出现更多的奇迹。
说了这么多关于JSX,它到底是神马呢?
1、JSX(Javascript XML)即可以在js中使用类似XML语法的标签,只是借用了XML的表现形式,与html的语法也很相近
2、JSX语法与Html几个不同的地方?
标签闭合,如
<br />
,<input type="text" />
,<img src="" />
不要在HTML模板中写JS关键字,所以
class
应该用className
,for
应该用htmlFor
注释写法:
{/* 说明 */}
style 属性接收的是一个 key-value 的JS对象,而不是字符串,如:
style=
注: 类似于font-size这种带横杠的属性,则应写为``,给属性也加引号
3、为什么推荐使用JSX?
基于JSX的以下几个特点:
- 使用了类XML的语法,易接受,结构清晰
- 增强了js的语义
- 抽象程度高
- 代码模块化
已经搭建了简单的环境可以体验一把ReactJs,并介绍了更直观的JSX语法,下面展开介绍下更多ReactJs特性:
1、组件的生命周期:组件所有的状态组合起来就是组件的生命周期,初始化 -》运行中-》销毁
各生命周期中的钩子函数及其用法:
初始化阶段:
getDefaultProps 在createClass时调用,不是在实例化时调用,且只会调用一次,实例之间共享引用
getInitialState 初始化每个实例的状态,不同实例不同状态
componentWillMount 可以修改状态
render 只能访问this.props和this.state,只有一个顶层组件,不允许修改状态和DOM输出(会使逻辑复杂)
从 render() 中返回的内容并不是实际渲染出来的子组件实例。从 render() 返回的仅仅是子组件层级树实例在特定时间的一个描述。
componentDidMount 组件装载完,DOM已显示至页面中,此时可以操作DOM
getDefaultProps:function(){
console.log(1);
return {name:'react'};
},
getInitialState:function(){
console.log(2);
return {age:12,sex:'女'};
},
componentWillMount:function(){
console.log(3);
this.setState({sex:'男'});
},
componentDidMount:function(){
console.log(5);
$(React.findDOMNode(this)).append("i am learning a class");
},
render:function(){
console.log(4);
return (
<div ref="he">hello {this.props.name?this.props.name:"world"}<br />{this.state.sex}</div>
)
}
});
上述例子中组件会按照输出为1,2,3,4,5的顺序执行对应的钩子函数。
运行中阶段:
1》 componentWillReceiveProps 在组件接收到属性之前,可以修改新属性、修改状态,如父组件在修改子组件属性之前 2》shouldComponentUpdate 若在该函数中return false,则不会调用 3》componentWillUpdate 不能修改属性和状态 4》render根据diff算法重新渲染虚拟DOM 5》componentDidUpdate 真实DOM已经完成更新,可以操作DOM结构
var Hello = React.createClass({
componentWillReceiveProps:function(newprops){
console.log(1);
console.log(newprops);
},
shouldComponentUpdate:function(){
console.log(2);
return true;
},
componentWillUpdate:function(){ //不能修改属性和状态
console.log(3);
},
componentDidUpdate:function(){
console.log(5);
$(React.findDOMNode(this)).append('what is a surprise');
},
componentWillUnmount:function(){
console.log("clear");
},
render:function(){
console.log(4);
return (
<div ref="he">hello {this.props.name?this.props.name:"world"}<br /></div>
)
}
});
var HelloUniverse = React.createClass({
getInitialState:function(){
return {name:''};
},
handlerChange:function(e){
this.setState({name: e.target.value}); //属性改变后会自动调用render
},
render:function(){
if(this.state.name=='123'){
return <div>123</div>
}
return(
<div>
<Hello name={this.state.name} />
<br />
<input type="text" onChange={this.handlerChange} />
</div>
)
}
});
销毁:componentWillUnmount 做一些清理工作
2、状态和属性:状态是组件本身维护的数据,当状态发生变化时,组件会相应的进行更新,而属性是由父组件传给子组件的,组件本身不能修改,可以理解为与生俱来的
相同点:都是纯js对象;都会触发render更新;都具有确定性(状态相同,结果相同)
何时用属性,何时用状态 状态转换时React会触发不同的钩子函数,从而让开发者有机会做出响应
3、组件嵌套
父组件和子组件间如何通信? 如何使用属性和委托来实现父子组件的通信 Mixin 代码复用,抽离通用代码,提高开发效率,但编写难度高,可能需要兼容多个组件,使得复杂度提高,降低了代码的可读性
父组件通过传递属性来跟子组件通信,而子组件通过调用父组件的函数来通信
例:
//子组件
var GenderSelect = React.createClass({
render:function(){
return (
<select onChange={this.props.handlerSelect}>
<option value="男">男</option>
<option value="女">女</option>
</select>
)
}
});
//父组件
var App = React.createClass({
getInitialState:function(){
return {
name:'',
password:'',
gender:''
}
},
handlerChange:function(name,e){
var newState = {};
newState[name] = e.target.value;
this.setState({name:newState});
},
handlerSelect:function(e){
this.setState({gender: e.target.value}) ;
},
render:function(){
console.log(this.state);
return (
<form>
<input type="text" placeholder="" onChange={this.handlerChange.bind(this,'name')} />
<input type="password" placeholder="" onChange={this.handlerChange.bind(this,'password')} />
<GenderSelect handlerSelect={this.handlerSelect} />
</form>
)
}
});