React 高阶组件的使用

253 阅读2分钟

曾经有一次去面试,对方问了我一堆 React 理论, 其中就包括什么是高阶组件,我要么说的不清不楚要么直接说不会,结果…… (是真的)因为都是实践出真知,都没去理清概念。

什么是高阶组件

官方介绍:高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。 总结:高阶组件是接收组件并返回组件的函数式组件。

高阶组件长这样

const EnhancedComponent = higherOrderComponent(WrappedComponent);

像 Redux 的 connect 等也是高阶组件。

function App(props) {}

export default connect(
 state => {},
 dispatch => {},
)(App)

高阶组件的使用

src 目录下建一个 HocComponent.js 文件。

import React, {Component} from 'react';
const HocComponent = PropsComponent => {
 console.log('PropsComponent')
 return class extends Component {
  render() {
   return <PropsComponent {...this.props}/>
  }
 }
}
export default HocComponent

修改 App.js ,使用上面写的 HocComponent.js 包装起来。

import React from 'react';
import HocComponent from "./HocComponent";

function App() {
  return (
    <div className="App">
        {/* 省略代码 */}
    </div>
  );
}
export default HocComponent(App);

App 组件通过 HocComponent 包装,运行后,控制台会输出 “ PropsComponent ” 。那么形如这样 HocComponent 包装后的组件,就是一个高阶组件。HocComponent 接收一个 class 组件,并且返回了一个 class 组件。

像上面这样的方式称为调用传入的组件,不过实现高阶组件的方法有两种,除了上面这种,还有一种称为继承传入的组件。

修改 HocComponent.js 文件

import React, {Component} from 'react';
const HocComponent = PropsComponent => {
 console.log('PropsComponent')
 return class extends PropsComponent {}
}
export default HocComponent

改完后,突然一堆红……

经过测试,弱弱地想这是因为继承只接收 class 的组件,不能传递函数式组件。 修改 App.js 文件。

import React from 'react';
import HocComponent from "./HocComponent";

class App extends React.Component {
 render() {
  return (

    <div className="App">
        {/* 省略代码 */}
    </div>
  );
 }
}
export default HocComponent(App);

装饰器写法

高阶组件其实可以认为是装饰器的设计模式在 React 的实现。 装饰器的概念:装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。 ES7中添加了一个 decorator 的属性,使用 @ 符号表示。 因此 App.js 可以改写成


import React from 'react';
import HocComponent from "./HocComponent";

@HocComponent
class App extends React.Component {
 render() {
  return (
    <div className="App">
        {/* 省略代码 */}
    </div>
  );
 }
}
export default App;

改完后,又红了……

提示告诉我们,当前未启用对实验语法“decorators legacy”的支持。我们需要安装 @babel/plugin-proposal-decorators ,并配置 .babelrc

{
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "legacy": true
      }
    ]
  ]
}

重新运行,就可以了。