高阶组件简介

作者: 菜菜的小阿允 | 来源:发表于2020-11-02 16:20 被阅读0次
一、定义

高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。具体而言,高阶组件是参数为组件,返回值为新组件的函数,如:

const NewComponent = higherOrderComponent(OldComponent);
二、例子

高阶组件是一个函数(而不是组件),它接受一个组件作为参数,返回一个新的组件。这个新的组件会使用你传给它的组件作为子组件,我们可以看个例子来进一步理解一下。

  • 假设在src/wrapWithLoadData.js 文件中写一个HOC,要求NewComponent 会根据第二个参数 name 在挂载阶段从 localStorage 加载数据,并且 setState 到自己的 state.data 中,而渲染的时候将 state.data 通过 props.data 传给 WrappedComponent,如下:
import React, { Component } from 'react';
export default (WrappedComponent, name) => {
  class NewComponent extends Component {
    constructor () {
      super()
      this.state = { data: null }
    }

    componentWillMount () {
      let data = localStorage.getItem(name)
      this.setState({ data })
    }

    render () {
      return <WrappedComponent data={this.state.data} />
    }
  }
  return NewComponent;
}
  • 假如有一个组件的需求是挂载的时候从 localStorage 里面加载 username 字段作为 <input /> 的 value 值,现在有了 wrapWithLoadData,我们可以很容易地做到这件事情。只需要定义一个非常简单的 InputWithUserName,它会把 props.data 作为 <input /> 的 value 值。然把这个组件和 'username' 传给 wrapWithLoadData,wrapWithLoadData 会返回一个新的组件,我们用这个新的组件覆盖原来的 InputWithUserName,然后再导出去模块,我们可以在src/inputWithUserName.js 文件中这样写:
import wrapWithLoadData from './wrapWithLoadData';

class InputWithUserName extends Component {
  render () {
    return <input value={this.props.data} />
  }
}

InputWithUserName = wrapWithLoadData(InputWithUserName, 'username');
export default InputWithUserName;
  • 这个新的组件挂载的时候会先去 localStorage 加载数据,渲染的时候再通过 props.data 传给真正的 InputWithUserName,别人用这个组件的时候实际是用了被加工过的组件:
import InputWithUserName from './InputWithUserName';

class Index extends Component {
  render () {
    return (
      <div>
        用户名:<InputWithUserName />
      </div>
    )
  }
}
  • 如果现在我们需要另外一个文本输入框组件,它也需要 localStorage 加载 'content' 字段的数据。我们只需要定义一个新的 TextareaWithContent:
import wrapWithLoadData from './wrapWithLoadData';
class TextareaWithContent extends Component {
  render () {
    return <textarea value={this.props.data} />
  }
}
TextareaWithContent = wrapWithLoadData(TextareaWithContent, 'content');
export default TextareaWithContent;
  • 这样我们根本不需要重复写从 localStorage 加载数据字段的逻辑,直接用 wrapWithLoadData 包装一下就可以了。对于 InputWithUserName 和 TextareaWithContent 这两个组件来说,它们的需求有着一个相同的逻辑:“挂载阶段从 localStorage 中加载特定字段数据”。如果按照之前的做法,我们需要给它们两个都加上 componentWillMount 生命周期,然后在里面调用 localStorage。要是有第三个组件也有这样的加载逻辑,又得写一遍这样的逻辑。但有了 wrapWithLoadData 高阶组件,我们把这样的逻辑用一个组件包裹了起来,并且通过给高阶组件传入 name 来达到不同字段的数据加载。充分复用了逻辑代码。到这里,高阶组件的作用其实不言而喻,其实就是为了组件之间的代码复用。组件可能有着某些相同的逻辑,把这些逻辑抽离出来,放到高阶组件中进行复用。高阶组件内部的包装组件和被包装组件之间通过 props 传递数据。
三、高阶组件的灵活性

代码复用的方法、形式有很多种,可以用类继承来做到代码复用,也可以用分离模块的方式。但是高阶组件这种方式很有意思,也很灵活,它其实就是设计模式里面的装饰者模式,通过组合的方式达到很高的灵活程度。
假如现在需求变成了:需要先从 localStorage 中加载数据,再用这个数据去服务器取数据。

  • 我们可以在src/wrapWithAjaxData.js 文件中写一个wrapWithAjaxData 高阶组件:
import React, { Component } from 'react';
import ajax from 'Ajax';

export default (WrappedComponent, name) => {
  class NewComponent extends Component {
    constructor () {
      super()
      this.state = { data: null }
    }

    componentWillMount () {
      ajax.get('/data/' + this.props.data, (data) => {
        this.setState({ data })
      })
    }

    render () {
      return <WrappedComponent data={this.state.data} />
    }
  }
  return NewComponent;
}
  • 它会用传进来的 props.data 去服务器取数据。这时候如下修改 InputWithUserName:
import wrapWithLoadData from './wrapWithLoadData'
import wrapWithAjaxData from './wrapWithAjaxData'

class InputWithUserName extends Component {
  render () {
    return <input value={this.props.data} />
  }
}

InputWithUserName = wrapWithAjaxData(InputWithUserName);
InputWithUserName = wrapWithLoadData(InputWithUserName, 'username');
export default InputWithUserName;
  • 我们给 InputWithUserName 应用了两种高阶组件:先用 wrapWithAjaxData 包裹 InputWithUserName,再用 wrapWithLoadData 包含上次包裹的结果。它们的关系如下图:


  • 实际上最终得到的组件会先去 LocalStorage 取数据,然后通过 props.data 传给下一层组件,下一层用这个 props.data 通过 Ajax 去服务端取数据,然后再通过 props.data 把数据传给下一层,也就是 InputWithUserName。组件之间的数据流向如下图:


四、总结
  • 高阶组件就是一个函数,传给它一个组件,它返回一个新的组件。新的组件使用传入的组件作为子组件。
  • 高阶组件的作用是用于代码复用,可以把组件之间可复用的代码、逻辑抽离到高阶组件当中。新的组件和传入的组件通过 props 传递信息。
  • 高阶组件有助于提高我们代码的灵活性,逻辑的复用性。

相关文章

  • 2021-08-05-🦕🦕 react 高阶组件hotc和@装饰

    简介 高阶组件可以直接调用子组件属性方法;子组件通过 this.props.xxx调用高阶组件方法属性 高阶组件无...

  • 高阶组件简介

    一、定义 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API...

  • ES7 装饰器模式的配置

    装饰器模式简介 在使用 React 框架编程中,我们用高阶组件的时候,使用时往往需要用高阶组件函数包裹当前组件来导...

  • React-Native 高阶组件

    高阶函数 高阶组件(属性代理)普通组件还可以向高阶组件传值 高阶组件(反向继承) 普通组件的 static 方法怎...

  • React高阶组件HOC

    高阶组件本质是函数,参数是 组件1 返回组件2,高阶组件是为了复用通用逻辑高阶组件eg:import React,...

  • react与vue中高阶组件的对比

    由高阶函数引申出来的高阶组件 高阶组件本质上也是一个函数,并不是一个组件,且高阶组件是一个纯函数。高阶组件,顾名思...

  • React——第三阶段(1)(高阶组件、context)

    根据胡子大哈的文章学习,感谢大胡分享胡子大哈-高阶组件、context 高阶组件 什么是高阶组件 高阶组件就是一个...

  • React 高阶组件(HOC)

    什么是高阶组件? 高阶组件(Higher-Order Components,简称HOC):简而言之,高阶组件就是加...

  • 高阶组件

    高阶组件 先来引入这个概念 高阶函数是什么? 高阶函数就是一个函数返回一个函数eg: 高阶组件 类同 高阶组件就是...

  • React 进阶之高阶组件

    高阶组件 HOC 高阶组件(HOC)是react中的高级技术,用来重用组件逻辑。但高阶组件本身并不是React A...

网友评论

    本文标题:高阶组件简介

    本文链接:https://www.haomeiwen.com/subject/vjlfyktx.html