全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

深入理解React高阶组件

1.在React中higher-order component (HOC)是一种重用组件逻辑的高级技术。HOC不是React API中的一部分。HOC是一个函数,该函数接收一个组件并且返回一个新组件。在React中,组件是代码复用的基本单位。

2.为了解释HOCs,举下面两个例子

CommentList组件会渲染出一个comments列表,列表中的数据来自于外部。

class CommentList extends React.Component {

  constructor() {

   super();

   this.handleChange = this.handleChange.bind(this);

   this.state = {

    // "DataSource" is some global data source

    comments: DataSource.getComments()

   };

  }

 

  componentDidMount() {

   // Subscribe to changes

   DataSource.addChangeListener(this.handleChange);

  }

 

  componentWillUnmount() {

   // Clean up listener

   DataSource.removeChangeListener(this.handleChange);

  }

 

  handleChange() {

   // Update component state whenever the data source changes

   this.setState({

    comments: DataSource.getComments()

   });

  }

 

  render() {

   return (

    <div>

     {this.state.comments.map((comment) => (

      <Comment comment={comment} key={comment.id} />

     ))}

    </div>

   );

  }

 } 

 接下来是BlogPost组件,这个组件用于展示一篇博客信息

class BlogPost extends React.Component {

  constructor(props) {

   super(props);

   this.handleChange = this.handleChange.bind(this);

   this.state = {

    blogPost: DataSource.getBlogPost(props.id)

   };

  }

 

  componentDidMount() {

   DataSource.addChangeListener(this.handleChange);

  }

 

  componentWillUnmount() {

   DataSource.removeChangeListener(this.handleChange);

  }

 

  handleChange() {

   this.setState({

    blogPost: DataSource.getBlogPost(this.props.id)

   });

  }

 

  render() {

   return <TextBlock text={this.state.blogPost} />;

  }

 } 

这两个组件是不一样的,它们调用了DataSource的不同方法,并且它们的输出也不一样,但是它们中的大部分实现是一样的:

1.装载完成后,给DataSource添加了一个change listener
2.当数据源发生变化后,在监听器内部调用setState
3.卸载之后,移除change listener

可以想象在大型应用中,相同模式的访问DataSource和调用setState会一次又一次的发生。我们希望抽象这个过程,从而让我们只在一个地方定义这个逻辑,然后在多个组件中共享。

接下来我们写一个创建组件的函数,这个函数接受两个参数,其中一个参数是组件,另一个参数是函数。下面调用withSubscription函数

const CommentListWithSubscription = withSubscription(

 CommentList,

 (DataSource) => DataSource.getComments()

);

 

const BlogPostWithSubscription = withSubscription(

 BlogPost,

 (DataSource, props) => DataSource.getBlogPost(props.id)

); 

调用withSubscription传的第一个参数是wrapped 组件,第二个参数是一个函数,该函数用于检索数据。

当CommentListWithSubscription和BlogPostWithSubscription被渲染,CommentList和BlogPost会接受一个叫做data的prop,data中保存了当前从DataSource中检索出的数据。withSubscription代码如下:

// This function takes a component...

function withSubscription(WrappedComponent, selectData) {

 // ...and returns another component...

 return class extends React.Component {

  constructor(props) {

   super(props);

   this.handleChange = this.handleChange.bind(this);

   this.state = {

    data: selectData(DataSource, props)

   };

  }

 

  componentDidMount() {

   // ... that takes care of the subscription...

   DataSource.addChangeListener(this.handleChange);

  }

 

  componentWillUnmount() {

   DataSource.removeChangeListener(this.handleChange);

  }

 

  handleChange() {

   this.setState({

    data: selectData(DataSource, this.props)

   });

  }

 

  render() {

   // ... and renders the wrapped component with the fresh data!

   // Notice that we pass through any additional props

   return <WrappedComponent data={this.state.data} {...this.props} />;

  }

 };

} 

 HOC并没有修改输入的组件,也没有使用继承去重用它的行为。HOC只是一个函数。wrapped 组件接受了容器的所以props,同时还接受了一个新的prop(data),data用于渲染wrapped 组件的输出。HOC不关心数据怎么使用也不关心数据为什么使用,wrapped组件不关心数据是哪儿得到。

因为withSubscription只是一个常规的函数,你能添加任意个数的参数。例如,你能让data prop的名字是可配置的,从而进一步将HOC与wrapped组件隔离。

或者接受一个配置shouldComponentUpdate,或者配置数据源的参数

使用高阶组件时有些需要注意的地方。

1.不要修改原始组件,这一点很重要

有如下例子:

function logProps(InputComponent) {

 InputComponent.prototype.componentWillReceiveProps = function(nextProps) {

  console.log('Current props: ', this.props);

  console.log('Next props: ', nextProps);

 };

 // The fact that we're returning the original input is a hint that it has

 // been mutated.

 return InputComponent;

}

 

// EnhancedComponent will log whenever props are received

const EnhancedComponent = logProps(InputComponent); 

这里存在一些问题,1.输入的组件不能与增强的组件单独重用。2.如果给EnhancedComponent应用其他的HOC,也会改变componentWillReceiveProps。

这个HOC对函数类型的组件不适用,因为函数类型组件没有生命周期函数HOC应该使用合成代替修改——通过将输入的组件包裹到容器组件中。

function logProps(WrappedComponent) {

 return class extends React.Component {

  componentWillReceiveProps(nextProps) {

   console.log('Current props: ', this.props);

   console.log('Next props: ', nextProps);

  }

  render() {

   // Wraps the input component in a container, without mutating it. Good!

   return <WrappedComponent {...this.props} />;

  }

 }

} 

这个新的logProps与旧的logProps有相同的功能,同时新的logProps避免了潜在的冲突。对class类型的组件和函数类型额组件同样适用。

2.不要在render方法中使用HOCs

React的diff算法使用组件的身份去决定是应该更新已存在的子树还是拆除旧的子树并装载一个新的,如果从render方法中返回的组件与之前渲染的组件恒等(===),那么React会通过diff算法更新之前渲染的组件,如果不相等,之前渲染的子树会完全卸载。 

render() {

 // A new version of EnhancedComponent is created on every render

 // EnhancedComponent1 !== EnhancedComponent2

 const EnhancedComponent = enhance(MyComponent);

 // That causes the entire subtree to unmount/remount each time!

 return <EnhancedComponent />;

} 

 在组件定义的外部使用HOCs,以至于结果组件只被创建一次。在少数情况下,你需要动态的应用HOCs,你该在生命周期函数或者构造函数中做这件事

3.静态方法必须手动复制

有的时候在React组件上定义静态方法是非常有用的。当你给某个组件应用HOCs,虽然原始组件被包裹在容器组件里,但是返回的新组件不会有任何原始组件的静态方法。

// Define a static method

WrappedComponent.staticMethod = function() {/*...*/}

// Now apply an HOC

const EnhancedComponent = enhance(WrappedComponent);

 

// The enhanced component has no static method

typeof EnhancedComponent.staticMethod === 'undefined' // true 

 为了让返回的组件有原始组件的静态方法,就要在函数内部将原始组件的静态方法复制给新的组件。

function enhance(WrappedComponent) {

 class Enhance extends React.Component {/*...*/}

 // Must know exactly which method(s) to copy :(

  // 你也能够借助第三方工具

 Enhance.staticMethod = WrappedComponent.staticMethod;

 return Enhance;

} 

 4.容器组件上的ref不会传递给wrapped component

虽然容器组件上的props可以很简单的传递给wrapped component,但是容器组件上的ref不会传递到wrapped component。如果你给通过HOCs返回的组件设置了ref,这个ref引用的是最外层容器组件,而非wrapped 组件

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# React高阶组件  # react  # 高阶组件使用  # React 高阶组件HOC用法归纳  # React高阶组件的使用浅析  # React组件重构之嵌套+继承及高阶组件详解  # React学习笔记之高阶组件应用  # 浅谈React高阶组件  # React 高阶组件入门介绍  # react高阶组件经典应用之权限控制详解  # React HOC高阶组件深入讲解  # 子树  # 是一个  # 也不  # 周期函数  # 你给  # 不关心  # 的是  # 是一种  # 也会  # 第一个  # 让我们  # 多个  # 你也  # 其他的  # 要在  # 你能  # 这两个  # 这件事  # 第二个  # 能让 


相关文章: 全景视频制作网站有哪些,全景图怎么做成网页?  网站制作软件有哪些,制图软件有哪些?  建站之星代理商如何保障技术支持与售后服务?  宝塔Windows建站如何避免显示默认IIS页面?  开源网站制作软件,开源网站什么意思?  C++时间戳转换成日期时间的步骤和示例代码  如何在服务器上三步完成建站并提升流量?  专业网站制作企业网站,如何制作一个企业网站,建设网站的基本步骤有哪些?  如何通过云梦建站系统实现SEO快速优化?  javascript中的try catch异常捕获机制用法分析  成都网站制作价格表,现在成都广电的单独网络宽带有多少的,资费是什么情况呢?  如何在阿里云完成域名注册与建站?  电视网站制作tvbox接口,云海电视怎样自定义添加电视源?  建站之星代理如何优化在线客服效率?  建站主机选哪家性价比最高?  如何制作公司的网站链接,公司想做一个网站,一般需要花多少钱?  如何在IIS中新建站点并配置端口与IP地址?  购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?  建站主机CVM配置优化、SEO策略与性能提升指南  如何彻底卸载建站之星软件?  沈阳个人网站制作公司,哪个网站能考到沈阳事业编招聘的信息?  重庆市网站制作公司,重庆招聘网站哪个好?  网站制作中优化长尾关键字挖掘的技巧,建一个视频网站需要多少钱?  如何在万网自助建站平台快速创建网站?  北京制作网站的公司,北京铁路集团官方网站?  MySQL查询结果复制到新表的方法(更新、插入)  c++怎么用jemalloc c++替换默认内存分配器【性能】  SAX解析器是什么,它与DOM在处理大型XML文件时有何不同?  如何快速搭建虚拟主机网站?新手必看指南  c++怎么使用类型萃取type_traits_c++ 模板元编程类型判断【方法】  网站建设设计制作营销公司南阳,如何策划设计和建设网站?  建站主机系统SEO优化与智能配置核心关键词操作指南  红河网站制作公司,红河事业单位身份证如何上传?  高性价比服务器租赁——企业级配置与24小时运维服务  建站之星官网登录失败?如何快速解决?  微信小程序 五星评分(包括半颗星评分)实例代码  建站主机选择指南:服务器配置与SEO优化实战技巧  韩国服务器如何优化跨境访问实现高效连接?  如何获取上海专业网站定制建站电话?  如何在Golang中实现微服务服务拆分_Golang微服务拆分与接口管理方法  常州自助建站:操作简便模板丰富,企业个人快速搭建网站  高端云建站费用究竟需要多少预算?  我的世界制作壁纸网站下载,手机怎么换我的世界壁纸?  建站之星如何开启自定义404页面避免用户流失?  制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?  如何快速打造个性化非模板自助建站?  制作旅游网站html,怎样注册旅游网站?  建站之星3.0如何解决常见操作问题?  开封网站制作公司,网络用语开封是什么意思?  网站网页制作电话怎么打,怎样安装和使用钉钉软件免费打电话? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。