React 介绍及实践教程
概述React 是近期非常热门的一个前端开发框架,其本身作为 MVC 中的 View 层可以用来构建 UI,也可以以插件的形式应用到 Web 应用非 UI 部分的构建中,轻松实现与其他 JS 框架的整合,比如 AngularJS。同时,React 通过对虚拟 DOM 中的微操作来实对现实际 DOM 的局部更新,提高性能。其组件的模块化开发提高了代码的可维护性。单向数据流的特点,让每个模块根据数据量自动更新,让开发者可以只专注于数据部分,改善程序的可预测性。 React 简介虚拟Dom(Virtual DOM)传统的web应用,操作DOM一般都是直接进行更新操作的,但对DOM进行更新通常是比较昂贵的。而React为了尽可能减少对DOM的操作,提供了一种强大的方式来更新DOM,代替直接的DOM操作,这就是Virtual DOM,一个轻量级的虚拟的DOM。 虚拟 DOM 是一个 JavaScript 的树形结构,包含了 React 元素和模块。组件的 DOM 结构就是映射到对应的虚拟 DOM 上,React 通过渲染虚拟 DOM 到浏览器,使得用户界面得以显示。与此同时,React 在虚拟的 DOM 上实现了一个 diff 算法,当要更新组件的时候,会通过 diff 寻找到要变更的 DOM 节点,再把这个修改更新到浏览器实际的 DOM 节点上,所以在 React 中,当页面发生变化时实际上不是真的渲染整个 DOM 树。 那为什么采用虚拟DOM会加快速度呢? 传统的web应用和采虚拟DOM技术的对比图: React组件React 中最基础最重要的就是 Component 了,它的构造和功能相当于 AngularJS 里面的 Directive,或是其他 JS 框架里面的 Widgets 或 Modules。Component 可以认为是由 HTML、CSS、JS 和一些内部数据组合而成的模块。当然 Component 也可以由很多 Component 组建而成。不同的 Component 既可以用纯 JavaScript 定义,也可以用特有的 JavaScript 语法 JSX 创建而成。关于 JSX,我们会在后面加以详细介绍。 为了更好的理解组件的概念,我们来看一个实例。 如图,在上面的实例中,当用户把鼠标移动到底部的颜色条上时,上方方框内会提示对应的颜色。最外面一层父级 Component 称为 ColorPanel,同时它包含了两个子 Component:上方的 ColorDisplay 和下方的 ColorBar。 创建一个 Componentvar ColorPanel = React.createClass({
render: function() {
return (
<div>
Color Panel
</div>
)
}
});
React.render(<ColorPanel/>,document.getElementById('demo'));
说明:通过 createClass 方法来创建了一个 Component。其中,createClass 需要传入一个 object 对象,这个对象可以定义不同的属性,render 方法是必须存在的,因为 render 方法的返回值代表的是 Component 的 template。 看到这里,您可能会觉得疑惑:为什么 JavaScript 代码中嵌入了 HTML 标签?其实这段嵌套在在 render 方法里面的并非真正意义上的 HTML,React 称之为“JSX”。JSX 可以允许把 HTML 类似的语法转换为轻量级的 JavaScript 对象。 使用JSX 转化成 JavaScript 的方式来创建 Component。 var ColorPanel = React.createClass({
displayName: "ColorPanel",render: function() {
return React.createElement("div",null,"Color Panel");
}
});
React.render(<ColorPanel/>,document.getElementById('demo'));
使用 JSX,开发人员还可以跳出 HTML 节点的限制自定义 Component。 给 Component 添加 state对于 UI 界面元素的诸多状态使得维护 UI 页面变的十分困难, React 却让着一切变的轻松起来。因为在 React 中,每一个 Component 都会维护自己的 state,当子 Component 需要这些 state 作为 props 时,则将其顺序传递下去。换句话说,如果有多个层级的 Component,它们公共的父级 Component 负责管理 state,然后通过 props 把 state 传递到子 Component 中。 为Component 添加 state: var ColorPanel = React.createClass({
getInitialState: function() {
return {
selectedColor: 'red'
}
},render: function() {
return (
<div>
{this.state.selectedColor}
</div>
)
}
});
React.render(<ColorPanel/>,document.getElementById('demo'));
我们通过创建组件时添加了一个 getInitialState 方法,来设置 Component 的 state 的,它返回的是一个对象包含了 Component 的 data 或者 state 值。在本例中,通过这个方法告诉 Component 需要保存一个叫 selectedColor 的对象,在 Component 的 render 方法中就可以通过{this.state.selectedColor}来使用。 从父 Component 中获取 StateReact 里有一个非常常用的模式就是对组件做一层抽象。组件对外公开一个简单的属性(Props)来实现功能,但内部细节可能有非常复杂的实现。 通过 props,React 框架可以保持良好的数据的直线传递——在最顶层的父级 Component 中处理所需要使用的特殊数据,当子的 Component 也需要使用时就把它们通过 props 来传递下去。 事实上 props 对于 Component 就像 Attribute 对于 HTML 一样,当我们提供了 property 的 name 和 value 时就传递到 Component 里面了。在 Component 里面通过 this.props 来获取 Properties。 从父节点中获取 state实例: var ColorPanel = React.createClass({
render: function() {
return (
<div>
<ColorBar colors={this.props.colors} />
</div>
);
},});
var colors = [
{id: 1,value: 'red',title: 'red'},{id: 2,value: 'blue',title: 'blue'},{id: 3,value: 'green',title: 'green'},{id: 4,value: 'yellow',title: 'yellow'},{id: 5,value: 'pink',title: 'pink'},{id: 6,value: 'black',title: 'black'}
];
React.render(<ColorPanel colors={colors}/>,document.getElementById('demo'));
我们可以通过改变 render 函数的内容来改变组件的行为。但是如果想要根据外部的信息来改变组件的行为,就需要使用 Properties。 var ColorPanel = React.createClass({
getDefaultProps: function() {
return {
colors: [
{id: 1,title: 'black'}
]
}
},render: function() {
return (
<div>
<ColorBar colors={this.props.colors} />
</div>
);
},});
React.render(<ColorPanel/>,document.getElementById('demo'));
Data Flow(单向数据流)传统的MVC开发模式: 到了 Flux 当中,除了名字改变了,重要的是大量的 Model 归到了 Store,View 也统一了,从而得到了所谓单向的数据流,就是 Model 和 View 之间关系非常清晰了。React 标榜自己是 MVC 里面 V 的部分,那么 Flux 就相当于添加 M 和 C 的部分,Flux 是 Facebook 使用的一套前端应用的架构模式。 React采用单向的数据流,即父节点传递到子节点的传递,因此更加灵活便捷,也提高了代码的可控性。简单的总结下单向数据流的流程如下:Action -> Dispatcher -> Store -> View FluxFlux 其实就是一种单向数据流的模式。与常见的 View 和 Store 相互交互的 MVC 模式不同的是,Flux 引入了 Dispatcher。用户在 View 上的操作,不会直接引起 Store 的变化,而是通过 Action 触发在 Dispatcher 上注册的回调函数,从而触发 Store 数据的更新,最终组件会重新渲染。这样一来,即可以保证数据流是单向流通的。Flux 相对于 MVC,让事情变得更加可以预见。 Flux数据单向数据流流程图: 当用户和 View(Component)交互的时候,View 会触发一个 Action 到中央 Dispatcher。然后将 Action 再分配到保存着应用的数据和业务逻辑的 Store 里面,Store 内数据的更新会引起所有 View 的更新。这个对 React 这种申明式的语法非常适用,这样就允许 Store 在更新的时候,不用去关注不同的 View 和 State 是如何交互的。 组件的生命周期每个组件都有自己的生命周期,在此期间 React 提供了很多方法用于对不同阶段的组件加以操作。 组件的生命周期主要可以分为三个阶段:Mounting、Updating、Unmounting。React 在每一阶段开始前提供了will 方法用于执行恰好在这一阶段开始前需要实行的操作,为每一段结束之后提供 did 方法用于执行恰好这一阶段结束时需要实现的操作。 Mounting阶段:Component 通过 React.createClass 被创建出来,然后调用 getInitialState 方法初始化 this.state。在 Component 执行 render 方法之前,通过调用 componentWillMount(方法修改 state 状态),然后执行 render。Reder 的过程即是组件生成 HTML 结构的过程。在 render 之后,Component 会调用 componentDidMount 方法。在这个方法执行之后,开发人员才能通过 this.getDOMNode()获取到组件的 DOM 节点。 Updating阶段:当有数据源变化时就会调用Updating方法。Component 的 componentWillReceiveProps 方法会监听组件中 props。监听到 props 发生修改,它会比对新的数据与之前的数据之间是否存在差别进而修改 state 的值。当比对的结果为数据变化需要对 Component 对应的 DOM 节点做出修改的时候,shouldCoponentUpdate 方法它会返回 true 用于触发 componentWillUpdate 和 componentDidUpdate 方法。在默认的情况下 shouldComponentUpdate 返回为 true。有些特殊的情况是当 component 中的 props 发生修改,但是其本身数据并没有改变,或者是开发人员手工设置 shouldComponentUpdate 为 false 时,React 就不会更新这个 component 对应的 DOM 节点了。与 componentWillMount 和 componentDidMount 相类似,componentWillUpdate 和 componentDidUpdate 也分别在组件更新的 render 过程前后执行。 UnMounting 阶段:当开发人员需要将 component 从 DOM 中移除时,就会触发 UnMounting 阶段。在这个阶段中,React 只提供了一个 componentWillUnmount 方法在卸载和销毁这个 component 之前触发,用于删除 component 中的 DOM 元素等。 JSX简介关于Jsx的介绍请查看JSX简介 React 实例通过上面的介绍我们对React 有了一个初步的了解,下面我们通过一个颜色版的改变实例来讲讲React。 <script type="text/jsx" src="js/colorBar.jsx"></script>
<script type="text/jsx" src="js/colorDisplay.jsx"></script>
<script type="text/jsx" src="js/colorPanel.jsx"></script>
colorPanel.jsx: var ColorPanel = React.createClass({
getDefaultProps: function() {
return {
colors: [
{id: 1,value: 'red',value: 'blue',value: 'green',value: 'yellow',value: 'pink',value: 'black',title: 'black'}
],defaultColorId: 1
}
},getInitialState: function() {
return {
selectedColor: this.getSelectedColor(this.props.defaultColorId)
}
},getSelectedColor: function(colorId) {
if(!colorId)
return null;
var length = this.props.colors.length;
for(var i = 0; i< length; i++) {
if(this.props.colors[i].id === colorId)
break;
}
return this.props.colors[i];
},shouldComponentUpdate: function(nextProps,nextState) {
return this.state.selectedColor.id !== nextState.selectedColor.id;
},render: function() {
console.log('Render Color Panel');
return (
<div>
<ColorDisplay selectedColor={this.state.selectedColor}/>
<ColorBar colors={this.props.colors} onColorHover={this.onColorHover} />
</div>
);
},onColorHover: function(colorId) {
this.setState({selectedColor: this.getSelectedColor(colorId)});
}
});
React.render(<ColorPanel/>,document.getElementById('demo'));
colorBar.jsx: var ColorBar = React.createClass({
shouldComponentUpdate: function(nextProps,nextState) {
return false;
},render: function() {
console.log('Render Color Bar Component');
return (
<ul>
{this.props.colors.map(function(color){
return (
<li key={color.id}
onMouSEOver={this.props.onColorHover.bind(null,color.id)}
className={color.value}></li>
)
},this)}
</ul>
);
}
});
colorDisplay.jsx var ColorDisplay = React.createClass({
shouldComponentUpdate: function(nextProps,nextState) {
return this.props.selectedColor.id !== nextProps.selectedColor.id;
},render: function() {
console.log('Render Color Display Component');
return (
<div className="color-display">
<div className={this.props.selectedColor.value}>
{this.props.selectedColor.title}
</div>
</div>
);
}
});
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |