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

news/2024/7/5 6:54:27

在接触过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... 第四章

http://www.niftyadmin.cn/n/3367148.html

相关文章

web test automation test / QTP / IBM RFT / Selenium IDE / IOS appium / AU3

Selenium WebDriver / Selenium IDE http://www.ibm.com/developerworks/cn/web/1306_chenlei_webdriver/ Selenium VS Webdriver http://www.ibm.com/developerworks/cn/web/1309_fengyq_seleniumvswebdriver/ 表 1. WebDriver 查找页面元素 查找方式描述举例 (Java)By.id以元…

H5学习从0到1-H5的超链接以及图片链接(6)

链接内容 1.文本链接 2.图片链接 属性 href&#xff1a;指向另一个文档的链接 name&#xff1a;文档内部的链接 img标签属性 alt&#xff1a;替换文本属性 width&#xff1a;宽 height&#xff1a;高 代码实例 效果图 感谢阅读 喜欢小编文章的&#xff0c;可以点个订阅&#xf…

The requested profile pom.xml could not be activated because it does not exist. 解决方法

项目单击右键&#xff0c;属性中找到maven&#xff0c;把此处清空保存即可 转载于:https://www.cnblogs.com/loveBetty/p/9441852.html

压测工具之JMeter之环境配置及运行

一、下载JMeter 地址&#xff1a;http://jmeter.apache.org/download_jmeter.cgi 系统&#xff1a;win7 x64 在 Binaries 目录下选择一个合适自己系统的版本&#xff0c;不要下载 Source 因为会报一个源文件丢失的错误。如下 unable to access jarfile apachejmeter.jar 二、…

微信小程序之底部弹框预约插件

代码地址如下&#xff1a;http://www.demodashi.com/demo/13982.html 一、前期准备工作&#xff1a; 软件环境&#xff1a;微信开发者工具 官方下载地址&#xff1a;https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html 1、基本需求。 实现用户预约时间可选预约…

web test flow

web 测试相关工具 http://www.51testing.com/?uid-94273-action-spacelist-type-blog-itemtypeid-1730 Rational Compuware Mercury TeleLogic 华为 其他 测试管理 Test Manager QA Director TestDirector Doors G…

SylixOS SPI 总线框架浅析

修订历史版本 日期 原因V1.00 2018/8/18 创建文档 目 录1 SPI总线关键结构体 11.1 总线传输控制消息块 11.2 SPI总线适配器 21.3 SPI设备 32 SPI各个结构体之间的联系 32.1 总线链表 32.2 总线与设备 33 参考资料 4 1 SPI总线关键结构体1.1 总线传输控制消息块传输控制消息包括…

OS + Linux/Unix download tools curl / wget

s 用wget下载整个网站 http://zhangyafeikimi.iteye.com/blog/385353 wget下载整个网站 可以使用下面的命令 wget -r -p -k -np http://hi.baidu.com/phps , -r 表示递归下载,会下载所有的链接,不过要注意的是,不要单独使用这个参数,因为如果你要下载的网站也有别的网站的链接…