mixin的特性一直普遍存在于各类面向对象语言中。好比在Ruby中,include关键词便是mixin。是将一个模块混入到一个另外一个模块中,或是一个类中。为何编程语言要引入这样一种特性呢?事实上,包括C++等一些年龄较大的OOP语言,它们都有一个强大但危险的多重继承特性。在现代语言中,为了权衡利弊,大都舍弃了多重继承,只采用单继承,但单继承在实现抽象时有不少不方便的地方,为了弥补缺失,java引入了接口interface。其余一些语言则引入了像mixin的技巧。javascript
从上面的代码,咱们不难看出,对于广义的mixin方法,就是用赋值的方式将mixin对象里的方法都挂载到原对象上,来实现对对象的混入。java
从上述的实现,咱们能够联想到 underscore库中的extend 或 lodash库中的 assign方法,或者说ES6中的Object.assign()方法。react
React官方已不推荐使用Mixins的技术来实现代码的重用,Mixins技术有一系列的缺点,首先Mixins会形成命名冲突,若是你须要注入多个mixins,其中一个是本身的,另外的多是第三方的。那有可能在两个mixins里使用了相同名称的方法,这会使得其中的一个不起做用,而你能作的只有修改其中一个方法的名称。另外一方面,一个mixins一开始多是很是简单的,仅仅须要实现某一个功能,但当业务越加的复杂,须要往其中加入更多的方法的时候,就会变得很是复杂。针对这些困扰,React社区提出来新的方式来取代mixin,那就是高阶组件。编程
说到高阶组件,就先得说到高阶函数了,高阶函数是至少知足下列条件的函数在javascript这门函数为一等公民的语言中,高阶函数的使用仍是很是之多的,像咱们平时的回调函数等等,都用到了高阶函数的知识。咱们先来看一个简单的高阶函数redux
从上面的代码,咱们不难看出,对于广义的mixin方法,就是用赋值的方式将mixin对象里的方法都挂载到原对象上,来实现对对象的混入。从上述的实现,咱们能够联想到 underscore库中的extend 或 lodash库中的 assign方法,或者说ES6中的Object.assign()方法。设计模式
高阶组件实际上是差很少的用法,类比高阶函数的定义,高阶组件就是接受一个组件做为参数,在函数中对组件作一系列的处理,随后返回一个新的组件做为返回值。高阶组件(HOC)是 React 中用于重用组件逻辑的高级技术。 HOC 自己不是 React API 的一部分。 它们是从 React 构思本质中浮现出来的一种模式,这种模式是由React自身的组合性质必然产生的。具体来讲,高阶组件是一个函数,可以接受一个组件做为参数,在函数中对组件作一系列的处理,随后返回一个新的组件做为返回值。在咱们项目中使用react-redux框架的时候,有一个connect的概念,这里的connect其实就是一个高阶组件。也包括相似react-router-dom中的withRouter的概念。babel
组件Usual经过simpleHoc的包装,打了一个log... 那么形如simpleHoc就是一个高阶组件了,经过接收一个组件class Usual,并返回一个组件class。 其实咱们能够看到,在这个函数里,咱们能够作不少操做。 并且return的组件一样有本身的生命周期,function,另外,咱们看到也能够把props传给WrappedComponent(被包装的组件)。markdown
高阶组件能够看作是装饰器模式(Decorator Pattern)在React的实现。即容许向一个现有的对象添加新的功能,同时又不改变其结构,属于包装模式(Wrapper Pattern)的一种ES7中添加了一个decorator的属性,使用@符表示,能够更精简的书写。那上面的例子就能够改为 是一样的效果。固然兼容性是存在问题的,一般都是经过babel去编译的。 babel提供了plugin,transform-decorators-legacy。react-router
实现高阶组件的方法有以下两种:属性代理、反向继承。app
属性代理:高阶组件经过被包裹的React组件来操做props
属性代理有以下4点常见做用:
操做props
经过refs访问组件实例
提取state
用其余元素包裹WrappedComponent,实现布局等目的
能够经过传入 props 和回调函数把 state 提取出来使用ppHOC装饰器以后,组件的props被添加了name属性,能够经过下面的方法,将value和onChange添加到input上面 input会成为受控组件
反向继承:高阶组件继承于被包裹的React组件。
反向继承能够劫持被继承class的render内容,进行修改,过滤后,返回新的显示内容。之因此被称为渲染劫持是由于 HOC 控制着 WrappedComponent 的渲染输出,能够用它作各类各样的事。
如上代码。高阶组件返回的组件继承于 WrappedComponent 。由于被动地继承了 WrappedComponent,全部的调用都会反向,这也是种方法的由来。这种方法与属性代理不太同样。它经过继承WrappedComponent来实现,方法能够经过super来顺序调用。由于依赖于继承机制。HOC的调用顺序和队列是同样的。在由 render输出的任何 React 元素中读取、添加、编辑、删除 props读取和修改由 render 输出的 React 元素树有条件地渲染元素树把样式包裹进元素树,就行Props Proxy那样包裹其余的元素
一、两个页面UI几乎同样,功能几乎相同,仅仅几个操做不太同样,却写了两个耦合不少的页面级组件
二、以前写过一个组件A,作完上线,以后加了一个新需求,很奇怪要作的组件B跟A几乎如出一辙,但稍微有区别
三、Container解决不了的时候甚至不太优雅的时候
四、实现一个从loaclstorage返回记录的功能
五、Mobx-react、react-redux
A).Container解决不了的时候甚至不太优雅的时候。其实大部分时候包一层Container组件也能作到差很少的效果,好比操做props,渲染劫持。但其实仍是有很大区别的。好比咱们如今有两个功能的container,添加样式和添加处理函数的,对Usual进行包装.
B).mobx-react就是高阶组件是一个实际应用@observer装饰器将组件包装为高阶组件,传入组件MyComponent后,mobx-react会对其生命周期进行各类处理,并经过调用forceUpdate来进行刷新实现最小粒度的渲染。mobx提倡一份数据引用,而redux中则提倡immutable思想,每次返回新对象。
C).react-redux中的connect
D).connect([mapStateToProps],[mapDispatchToProps],[mergeProps],[options])(WrappedComponent)
例如,咱们把组件ComponentA链接到Redux上的写法相似于:
const ConnectedComponentA = connect(mapStateToProps,mapDispatchToProps)(ComponentA);
咱们能够把它拆分来看:
// connect 是一个函数,返回值enhance也是一个函数
const enhance = connect(mapStateToProps, mapDispatchToProps);
// 返回的函数就是一个高阶组件,该高阶组件返回一个与Redux store关联起来的新组件
const ConnectedComponentA = enhance(ComponentA);
connect这个函数会将一个React组件链接到Redux 的 store
这个函数会将一个React组件链接到Redux 的 store。在链接的过程当中,connect经过参数 mapStateToProps,从全局store中取出当前组件须要的state,并把state转化成当前组件的props;同时经过参数 mapDispatchToProps,把当前组件用到的Redux的action creators,以props的方式传递给当前组件。
一、高阶组件不会修改子组件,也不拷贝子组件的行为,建议使用组合。
二、要给hoc添加class名,便于debugger。
三、静态方法要复制。
四、refs不会传递。
五、不要在render方法内部使用高阶组件