深入理解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 组件

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

(0)

相关推荐

  • react高阶组件经典应用之权限控制详解

    前言 所谓高级组件,即:接受一个组件作为参数,并且其返回值也为一个react组件 而大家应该都知道,权限控制算是软件项目中的常用功能了.在网站中,权限控制一般分为两个维度:页面级别和页面元素级别. 我们来说说页面元素粒度的权限控制.在某个页面中,有个"创建用户"的按钮,管理员才能看到. 一般想到的做法类似这样 class Page extends Component{ render() { let hasCreatePermission = tool.getAuth("cre

  • 深入理解React高阶组件

    1.在React中higher-order component (HOC)是一种重用组件逻辑的高级技术.HOC不是React API中的一部分.HOC是一个函数,该函数接收一个组件并且返回一个新组件.在React中,组件是代码复用的基本单位. 2.为了解释HOCs,举下面两个例子 CommentList组件会渲染出一个comments列表,列表中的数据来自于外部. class CommentList extends React.Component { constructor() { super(

  • React 高阶组件入门介绍

    高阶组件的定义 HoC 不属于 React 的 API,它是一种实现模式,本质上是一个函数,接受一个或多个 React 组件作为参数,返回一个全新的 React 组件,而不是改造现有的组件,这样的组件被称为高阶组件.开发过程中,有的功能需要在多个组件类复用时,这时可以创建一个 Hoc. 基本用法 包裹方式 const HoC = (WrappendComponent) => { const WrappingComponent = (props) => ( <div className=&

  • 浅谈React高阶组件

    前段时间在工作中写Hybrid页面时遇到了这样的一个场景,公司需要一系列的活动组件,在每个组件注册的时候都需要调用App端提供的一个接口.一开始也考虑了几种方式,包括mixin.组件继承以及react高阶组件.但经过了种种衡量,最后选择使用了高阶组件的做法. 那什么是高级组件?首先你得先了解请求ES6中的class只是语法糖,本质还是原型继承.能够更好的进行说明,我们将不会修改组件的代码.而是通过提供一些能够包裹组件的组件, 并通过一些额外的功能来增强组件.这样的组件我们称之为高阶组件(High

  • React高阶组件使用教程详解

    目录 高阶组件(HOC) 概述 使用HOC解决横切关注点问题 不用改变原始组件使用组合 约定-将不相关的 props 传递给被包裹的组件 约定-最大化可组合性 约定-包装显示名称以便轻松调试 使用高阶组件的注意事项 高阶组件(HOC) 概述 是React复用组件逻辑的一种高级技巧,是一种基于React组合特性而形成的设计模式 高阶组件是参数为组件,返回值为新组件的函数 简单理解: 高阶组件本身是 函数,传参数是组件,返回值也是组件: 高阶组件不用关心数据是如何渲染的,只用关心逻辑即可 被包装的组

  • 利用React高阶组件实现一个面包屑导航的示例

    什么是 React 高阶组件 React 高阶组件就是以高阶函数的方式包裹需要修饰的 React 组件,并返回处理完成后的 React 组件.React 高阶组件在 React 生态中使用的非常频繁,比如react-router 中的 withRouter 以及 react-redux 中 connect 等许多 API 都是以这样的方式来实现的. 使用 React 高阶组件的好处 在工作中,我们经常会有很多功能相似,组件代码重复的页面需求,通常我们可以通过完全复制一遍代码的方式实现功能,但是这

  • React 高阶组件HOC用法归纳

    一句话介绍HOC 何为高阶组件(HOC),根据官方文档的解释:"高阶组件是react中复用组件逻辑的一项高级技术.它不属于react API的组成部分,它是从react自身组合性质中抽离出来的一种模式.具体来说,高阶组件是函数,它接受一个组件作为参数,然后返回一个新的组件 使用场景 将几个功能相似的组件里面的方法和react特性(如生命周期里面的副作用)提取到HOC中,然后向HOC传入需要封装的组件.最后将公用的方法传给组件. 优势 使代码简洁优雅.代码量更少 HOC(高阶组件) /* HOC(

  • React高阶组件的使用浅析

    目录 高阶函数 高阶组件 react常见的高阶函数 高阶组件形式 在学习高阶组件前,首先我们了解一下高阶函数 高阶函数 把一个函数作为另一个函数的参数,那么这个函数就是高阶函数 高阶组件 一个组件的参数是组件,并且返回值是一个组件,我们称这类组件为高阶组件 react常见的高阶函数 withRouter() memo() react-redux中connect 高阶组件形式 React中的高阶组件主要有两种形式:属性代理和反向继承 属性代理:一个函数接收一个WrappedComponent组件作

  • React 高阶组件与Render Props优缺点详解

    目录 高阶组件 增强型高级组件 注入型高阶组件 高阶组件 VS Render Props 总结 高阶组件 高阶组件(HOC)是一个接受组件作为参数并返回一个新组件的函数,如果多个组件有相同的逻辑,将这些逻辑用函数封装,使它们能跨组件共用,这种用法称为高阶组件.下面的代码演示什么是高阶组件: export default function WithPrintLog(InnerComponent) { return class extends React.Component{ componentDi

  • react高阶组件添加和删除props

    唠叨几句啦 在看程墨老师的深入浅出高阶组件,开头一点提了一个需要,创建两个高阶组件,一个能给传入的元素自定义添加props,一个是删除特定的props.我刚刚做了一下,发现高阶组件需要区分好传入的是class还是react element, 同时也需要注意好return回去的是啥.顺便提一下高阶组件的概念,就说一个函数,能够接受一个组件作为参数,然后返回的时候,这个组件就带有这个高阶组件给的某些特性.我理解就跟掉泥坑了,得带点土出来一个道理. 对比一下两个组件,贴代码时刻来啦 删除属性的高阶组件

随机推荐