react进阶漫谈
本文的关键内容:样式处理与css模块化、组件间通信(非flux架构)、组件抽象、组件性能优化以及React 动画五种内容。 1.样式处理与css模块化在react出现之前,我们写样式一般是将css分离的,并且用less/sass预处理器,我个人在用backbone等MV*框架的时候就习惯用less并且用nodejs配置一个模块用来编译less。 但这样写会有一些问题:
于是我们引入css modules。 简单的说,如果我们配置了css modules的话,那么你在css中写的类名和你在组件中写的 需要注意的是写法问题,这个时候我们就不能在jsx中仅仅用className了,css module实际上限制了我们必须要用 关于css modules的入门介绍,没错,阮一峰老师写了一份:http://www.ruanyifeng.com/blo... 另外,有的同学认为css modules并不够优雅,实际上上文的写法限定的问题就是一个麻烦事,所以我们可以用react-css-modules库,这个库解决了css modules的一些不是很好的问题,因为上手并不难,这里不详细介绍了(可以参考这里以及“深入react技术栈”73页) 2.组件间通信(非flux架构)接下来我们总结一下react组件间通信的几种方式,虽然现在有了redux等最佳实践,但是很多时候我们还是需要原生可用的组件通信机制。 父组件向子组件之间非常常见,通过props机制传递即可。 子组件向父组件通信
跨级组件通信
getChildContext(){ return{ color:"red",} }
没有层级关系的组件通信这回只能用事件机制了,虽然我之前分析过别的框架的事件机制部分都可以单独拎出来用,但是这里面实际上有好多方式。 我首先试了一下js-signals这个库,这个也是React团队使用的,用起来也还简单, const signals= require('signals'); var Signal = { started : new signals.Signal() }; 我们可以把接收事件的函数定义在组件B中: onStarted(param1,param2){ alert(param1 + param2); } constructor(props){ super(props); Signal.started.add(this.onStarted); //add listener } 然后在组件A中(注意dispatch的时候要保证B已经被构造出来了): handlethis () { Signal.started.dispatch('foo','bar'); //dispatch signal passing custom parameters } render(){ return ( <button onClick={this.handlethis}>发射事件</button> ) } 其实还有很多类似的组件,当然我们自己写一个功能弱的也不成问题,更多的方式,这篇文章介绍的不错。 3.组件抽象mixinmixin是一个饱受诟病的东西,另外蛋疼的是在ES6的写法下也不能用,笔者现在写react的时候都已经不用了,所以这里进行简单介绍。 我们可以通过在createClass的时候传入一个mixins数组,这个数组里是我们的一些通用的方法: React.createClass({ mixins:[method1,method2] //... }) 这在ES6的class形式下是不能“直接”使用的。 ES7 decorator 与 mixinES7 的 decorator,作用就是返回一个新的 descriptor,并把这个新返回的 descriptor 应用到目标方法上。稍后我们将会看到,decorator 并非只能作用到类的方法/属性上,它还可以作用到类本身。 当然,这个我只言片语肯定说不明白的,这个我要推荐淘宝前端团队的这篇文章。 另外,core-decorators这个库值得关注,它里面有一个mixin方法用于实现mixin,原理就是用了ES7 decorator,实现起来也不是非常复杂。 最后,提醒一下ES7 decorator虽然很酷,但是目前还处于提案阶段,虽然借助babel我们已经可以体验了,但是距离真正支持还有一段距离 高阶组件(HOC)这是一个颇值得一提的话题。 我们应该听说过高阶函数,这种函数接受函数作为输入,或者是输出一个函数,比如map、reduce以及sort等函数。 一个高阶组件只是一个包装了另外一个 React 组件的 React 组件, 这种包装通常有两种方式: 1、属性代理(Props Proxy):高阶组件操控传递给 WrappedComponent 的 props, 高阶组件的功能主要有以下几点: 1、代码复用,逻辑抽象,抽离底层准备(bootstrap)代码
3、State 抽象和更改
4、Props 更改
我在这里没有给出代码,为了避免文章过于冗长以及和网上其他专题文章大部分重复,我主要是进行一些总结,具体内容我这里仍然是推荐一篇文章 4.组件性能优化PureRenderPureRender这个概念实际上和纯函数有关,Pure指的是对同样的输入(对于react来说就是props和state)总是得到相同的输出,针对这个问题,React有一个 PureRenderMixin在这个时候要派上用场了,这是一个能够实现上述功能的官方插件,react是这样介绍它的:
实际上是通过一个浅比较来确定是不是该被渲染,这实际上是一个性能上的权衡和妥协,深比较真的是耗费太多(我们在下一节会提出一个更好的解决方案)。 import PureRenderMixin from 'react-addons-pure-render-mixin'; class FooComponent extends React.Component { constructor(props) { super(props); this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this); } render() { return <div className={this.props.className}>foo</div>; } } 我们可以在这里查看更多信息。 Immutable.js在传递数据的时候,我们可以用Immutable Data进一步提高性能。 Immutable.js定义了不可变对象,一个数据结构(MapListArraySet)一旦被定义,就不可变了,我们把它如果用于state,那么每次变化的时候需要将state整个重新赋值。 上文提到,在shouldComponentUpdate使用PureRenderMixin由于性能权衡我们只能使用浅比较,但是如果我们用了Immutable.js,我们有更好的方式:直接用 另外,由于Immutable.js中提供的数据结构是不可变的,我们不用担心js中源对象跟随引用对象的变化而变化的问题,也不用考虑函数中所谓的引用赋值,这给我们的编程带来了很多方便。 当然也有不方便的是Immutable.js的数据结构并不能和原生的数据结构混用,因此写法上需要格外注意,关于更多资料请看这里. 无状态组件生命周期让react的组件变得功能非常强大并且复杂,从而难以维护,而有的时候我们又要经常写一些自身没有状态,只从父组件接受props的组件,这种组件可以提高react的渲染性能,也被官方推荐。 const HelloWorld = (props) => <div>{props.name}</div> ReactDOM.render(<HelloWorld name="HelloWorld" />,App) 简单,高效,在有些不需要改变的地方,比如没有用户交互纯声明性质的内容,可以用无状态组件。 react的diff算法我们想要让效率更高,还要注意的一点就是要照顾react的diff算法,react虽然有一个复杂度仅为O(N)的diff算法,但是这个算法也不是万能的,我们要想让react效能最大化,就要去照顾这个diff算法。 总的说来,这个diff算法大概有三点实现概要:
5.React 动画缓动函数对于各种动画来说,缓动体验一般是: 动画的方式有css动画和js动画,但是很多时候我们都是一起用的,所以区分的太详细似乎必要性也不大。 成熟的动画库实际上动画经常是笔者比较忽视的一个方面,由于还没毕业,大多时候都是自己做小东西,最后动画就成了可有可无的环节,另外现在的各种动画库很多,方便到只需要一个class、只写一行代码就可以做出相对过得去的效果,自己也就疏于探索。 这部分内容主要推荐一些成熟的动画库。 首先是ReactCSSTransitionGroup,这个动画库提供了一些生命周期钩子,我们可以利用此加动画,具体学API的过程相当简单,我相信看懂上面各个部分的同学直接按照给出的链接肯定能顺利学会。 还有react-smooth动画库,这也是一个比较有意思的动画库,写法类似css的多关键帧动画。并且几种缓动函数动画这里都能实现。 react-motion也是一个值得推荐的动画库,如果想用spring动画这个似乎是更好的选择。 另外,不说react,还有一个让我印象深刻不得不提的就是vivus.js这个svg动画库,不得不说真是酷毙了。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |