React漫谈
02 September 2015
谈必及React。
React优势
- 快。Virtual DOM的原理是做一份DOM树的拷贝在 javascript 的内存里,当DOM需要被改变的时候,通过比较虚拟DOM得到两者的不同,根据这个不同来更新真实的DOM。 快的原因是虚拟DOM只更新了两次DOM不同的地方,深层次的原因是javascript很快,而浏览器操作DOM很慢。
- ‘learn once, write everywhere’。虽然讲ReactJs是js的产物,但是它已经基本跳出了web前端的范畴,可以是web, ios, android。重要的还有,它解决了困扰前端单页面应用的SEO问题,React在服务端可以通过renderToString方法把页面渲染出来。这样当爬虫爬到你的页面的时候,得到的将会是一个完整的页面,而不是一个需要执行的Js代码了。
- 新概念。感受新技术的魅力,Web Components, ECMA 2015, webpack, data flow等等概念都可以在React上得到体验。
Virtual DOM的性能瓶颈
虚拟DOM很快,但他并不是没有性能瓶颈,因为React在render之前会做虚拟DOM树的比较操作,如果数据并没有发生改变,做这个额外的比较操作无疑是会增加开销的。好在React给出了自己的解决方案,那就是shouldComponentUpdate,shouldComponentUpdate的含义是这样的,在Component接受到新的props或者state,将要渲染之前调用,如果返回 false,那么组件不会更新。这里shouldComponentUpdate传入了两个参数,nextProps和 nextState,我们可以通过拿到的参数和当前的props和state进行比较,判断如果相等,那么返回false,告知组件不去更新。你可以使用PureRenderMixin插件,来帮你重复执行这个操作。
var PureRenderMixin = require('react').addons.PureRenderMixin;
React.createClass({
mixins: [PureRenderMixin],
render: function() {
return <div className={this.props.className}>foo</div>;
}
});
不过通过PurePenderMixin你只能进行浅层次的比较,如果想要使用深层比较的话,数据层你可以采用immutable-js,然后再使用上react-immutable-render-mixin就可以进行深层次比较了。
智慧组件和木偶组件
在智慧组件和木偶组件的概念中,可复用的组件是木偶组件,而起到控制展示作用的是智慧组件。
木偶组件
- 不依赖任何Flux的actions和stores.
- 通常允许包含在props.children里.
- 接收数据和回调通过props.
- 独立样式,包含有自己的css文件.
- 通常自己没有state.
- 很少用其他的木偶组件.
- 比如:Page, Sidebar, Story, UserInfo, List.
智能组件
- 包含木偶组件或其他的智慧组件.
- 提供木偶组件Flux stores.
- 提供木偶组件Flux actions.
- 没有自己的css样式,或仅有布局的框架样式.
- 没有自己的Dom结构,只包含木偶组件.
- 比如:UserPage, FollowersSidebar, StoryContainer, FollowedUserList.
这样写的好处
- 解耦,在写应用的时候更好的理解各个Component的职责。
- 重用,木偶组件可以被不同的数据状态驱动。
- 木偶组件就像是在以一种搭积木的方式构建应用,不涉及到任何的业务逻辑。
- 强迫用这样一种形式把布局组件抽离出来,可以更好的重用布局结构。
路由
React经常被拿去做单页面应用,react-router是一个不错的React路由管理框架。
var routes = (
<Route handler={App} path="/">
<DefaultRoute handler={Home} />
<Route name="about" handler={About} />
<Route name="users" handler={Users}>
<Route name="recent-users" path="recent" handler={RecentUsers} />
<Route name="user" path="/user/:userId" handler={User} />
<NotFoundRoute handler={UserRouteNotFound}/>
</Route>
<NotFoundRoute handler={NotFound}/>
<Redirect from="company" to="about" />
</Route>
);
Router.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
// Or, if you'd like to use the HTML5 history API for cleaner URLs:
Router.run(routes, Router.HistoryLocation, function (Handler) {
React.render(<Handler/>, document.body);
});
移动端tap事件
做过移动端的同学都知道,ios在处理click事件的时候有300ms的延迟。在zepto的方案下我们会有一个tap事件去解决这个问题,而在React中我们可以使用react-tap-event-plugin
var React = require('react'),
injectTapEventPlugin = require("react-tap-event-plugin");
injectTapEventPlugin();
var Main = React.createClass({
render: function() {
return <button onTouchTap={this._handleTouchTap}>Tap Me</button>
},
_handleTouchTap: function() {
alert('Tap');
}
});
React.render(<Main />, document.body);
动画
React的动画库,react-tween-state.
var tweenState = require('react-tween-state');
var React = require('react');
var App = React.createClass({
mixins: [tweenState.Mixin],
getInitialState: function() {
return {left: 0};
},
handleClick: function() {
this.tweenState('left', {
easing: tweenState.easingTypes.easeInOutQuad,
duration: 500,
endValue: this.state.left === 0 ? 400 : 0
});
},
render: function() {
var style = {
position: 'absolute',
width: 50,
height: 50,
backgroundColor: 'lightblue',
left: this.getTweeningValue('left')
};
return <div style={style} onClick={this.handleClick} />;
}
});
延伸阅读
- Categories:
- frontend 19
- Tags:
- react 1