在接触过React项目后,大多数人都应该已经了解过或则用过了HOC(High-Order-Components)和FaCC(Functions as Child Components),由于这两个模式在大多数react的开源库里都存在。好比react-router里面的withRouter 就是典型的高阶组件,接受一个组件返回另一个通过加强后的组件。而react-motion中的Motion就是典型的FaCC的应用。html
HOC和FaCC二者作的事也是很是类似的,都是相似设计模式里面的装饰者模式。都是在原有的实例或则单元上进行功能的加强。react
固然不仅是一些开源库中会使用,在日常的代码编写中,也有不少地方是适用于使用HOC和FaCC去封装一些逻辑。好比数据埋点,新特性的toggle,获取转换数据等。对于加强代码可读性和逻辑复用来讲,很是有用的。git
高阶函数咱们都用过,就是接受一个函数而后返回一个通过封装的函数:github
const plus = first => second => (first + second) plus(1)(2) // 3
而高阶组件就是高阶函数的概念应用到高阶组件上:express
const withClassName = ComposedComponent => props => ( <ComposedComponent {...props} className='demo-class' /> ) // 使用 const Header = text => (<header>{text}</header>) const headerWitheClass = withClassName(Header)
接受一个组件返回一个通过包装的新组件。在咱们常用的withRouter
就是在原有组件props
上面在加上localtion
等属性。除了添加props之外高阶组件还能作到:设计模式
对于上面的前三点都比较好理解,解释一下第4点。好比你在render了一个页面以后,须要改变一下页面的title.这是单页应用广泛存在的一个需求,一般你能够在具体router库中使用hook去实现。固然也能够经过HOC来实现:性能优化
const withTitleChange = ComposedComponent => { return class extends React.Component { componentDidMount () { const { title } = this.props document.title = title } render () { const props = this.props return <ComposedComponent {...props} /> } } }
一样FaCC也是用于加强原有组件能力的一种模式,其主要功能的实如今于react的props.children能够是任何东西,包括函数。咱们能够拿上面class的例子用FaCC再实现一遍:react-router
const ClassNameWrapper = ({ children }) => children('demo-class') // 使用 const HeadWithClass = (props) => ( <ClassNameWrapper> {(class) => <header classNmae={class} ></header>} </ClassNameWrapper> )
在FaCC中你也能够像HOC同样在生命周期中作不少事对原有的组件进行封装,基本上HOC能作的FaCC也都能作。我所在的项目以前都是大范围的使用HOC,再通过一番讨论后,开始大范围的转变成FaCC。app
二者都是用来加强原有组件的,具体该使用那种?那种是正确的模式?社区关于这一点也有不少讨论,好比就有人说FaCC是反模式:Function as Child Components Are an Anti-Pattern。他给出的理由是children并不语义化,会形成困惑,而后他提出了Component Injection
的模式,有兴趣的同窗能够读一读。dom
具体从几个方面作一下对比:
组合阶段意思就是HOC,FaCC和要被加强的组件的组合时候。能够很明显发现,FaCC对于先后组件对接依赖信息显示的更多,相对而言更容易理解。而HOC,相互之间如何桥接,你必须得深刻到HOC内部读代码才能够知道这个HOC具体干了啥。
// HOC example import View from './View' const DetailPage = withServerData(withNavigator(View))
// FaCC example import View from './View' const DetailPage = props => ( <FetchServerData> { data => ( <Navigator> <View data={data} {...props} /> </Navigator> ) } </FetchServerData> )
若是在上面再增长2个HOC,上面组合的过程就变得十分难看。而FaCC相对而言,如何封装,数据源来自那里,组件接受了那些数据都比较显眼。
在HOC中咱们能接受到宿主的prop,由于props是从HOC往下传递的,因此咱们也有完整的生命周期,咱们可使用shouldComponentUpdate优化。而FaCC则否则,没法在其内部作比较props,除非在组合的时候外部在包一个组件才能进行比较props。
FaCC 在组合阶段相对HOC更为灵活,他并不规定被加强组件如何使用它传递下去的属性。而HOC基本上在编写完后就定死了。
另外,FaCC不会再去建立一个新的Component,而HOC会建立一个新的Component而后传递props下去。
社区中不少开源库已经使用了两种模式,也有不少的文章进行比较。也有不少激烈讨论,固然对于最后解决问题而言,两种模式都有好处。出于不一样的考虑,可能选择不同。
参考文章: