React中的函数子组件(FaCC)和高阶组件(HOC)

在打仗过React项目后,大多数人都应当已相识过或则用过了HOC(High-Order-Components)和FaCC(Functions as Child Components),由于这两个形式在大多数react的开源库里都存在。比方react-router内里的withRouter 就是典范的高阶组件,接收一个组件返回别的一个经由加强后的组件。而react-motion中的Motion就是典范的FaCC的运用。

HOC和FaCC二者做的事也是异常相似的,都是相似设想形式内里的装潢者形式。都是在原有的实例或则单位上举行功用的加强。

固然不只是一些开源库中会运用,在寻常的代码编写中,也有许多处所是适用于运用HOC和FaCC去封装一些逻辑。比方数据埋点,新特征的toggle,猎取转换数据等。关于加强代码可读性和逻辑复用来讲,异常有效的。

HOC

高阶函数我们都用过,就是接收一个函数然后返回一个经由封装的函数:

const plus = first => second => (first + second)
plus(1)(2) // 3

而高阶组件就是高阶函数的观点运用到高阶组件上:


const withClassName = ComposedComponent => props => (
   <ComposedComponent {...props} className='demo-class' />
)

// 运用
const Header = text => (<header>{text}</header>)
const headerWitheClass = withClassName(Header)

接收一个组件返回一个经由包装的新组件。在我们常常运用的withRouter就是在原有组件props上面在加上localtion等属性。除了增添props之外高阶组件还能做到:

  • 在真正挪用组件前后做一些事,比方埋点数据等
  • 推断组件是不是该render,或则应当render其他的东西,比方失足以后render毛病页面
  • 通报props并增添新的props
  • 不render组件,转而做一些其他的事变,比方衬着一个外部的dom

关于上面的前三点都比较好明白,解释一下第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

一样FaCC也是用于加强原有组件才的一种形式,其主要功用的完成在于react的props.children能够是任何东西,包含函数。我们能够拿上面class的例子用FaCC再完成一遍:

const ClassNameWrapper = ({ children }) => children('demo-class')

// 运用

const HeadWithClass = (props) => (
  <ClassNameWrapper>
    {(class) => <header classNmae={class} ></header>}
  </ClassNameWrapper>
)

在FaCC中你也能够像HOC一样在生命周期中做许多事对原有的组件举行封装,基本上HOC能做的FaCC也都能做。我地点的项目之前都是大范围的运用HOC,再经由一番议论后,最先大范围的转变成FaCC。

区分

二者都是用来加强原有组件的,详细该运用那种?那种是准确的形式?社区关于这一点也有许多议论,比方就有人说FaCC是反形式:Function as Child Components Are an Anti-Pattern。他给出的理由是children并不语义化,会形成疑心,然后他提出了Component Injection的形式,有兴致的同砚能够读一读。

详细从几个方面做一下对照:

  1. 组合阶段

组合阶段意义就是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相对而言,怎样封装,数据源来自那边,组件接收了那些数据都比较显眼。

  1. 机能优化

在HOC中我们能接收到宿主的prop,由于props是从HOC往下通报的,所以我们也有完全的生命周期,我们能够运用shouldComponentUpdate优化。而FaCC则不然,没法在其内部做比较props,除非在组合的时刻外部在包一个组件才举行比较props。

  1. 天真性

FaCC 在组合阶段相对HOC更加天真,他并不划定被加强组件怎样运用它通报下去的属性。而HOC基本上在编写完后就定死了。

别的,FaCC不会再去建立一个新的Component,而HOC会建立一个新的Component然后通报props下去。

总结

社区中许多开源库已运用了两种形式,也有许多的文章举行比较。也有许多猛烈议论,固然关于末了解决问题而言,两种形式都有优点。出于差别的斟酌,能够挑选不一样。

参考文章:

  1. http://rea.tech/functions-as-…
  2. http://rea.tech/reactjs-real-…
  3. https://medium.com/merrickchr…
  4. http://www.ituring.com.cn/boo… 第四章
    原文作者:hiluluke
    原文地址: https://segmentfault.com/a/1190000016269347
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞