写在前面

高阶组件简称为 HOC,即 High Order Component ,是 React 中,高阶组件是一个函数,其接收的参数为一个组件,并返回一个组件。

HOC 是 react 中用于复用组件逻辑的一种高级技巧。

1. 为什么使用 HOC

为什么使用 HOC,简单来说,就是为了减少代码的重复。但是这种减少代码重复的方式是通过代码逻辑的复用实现的。

组件化思想就是减少代码重复的一种方式,对象的继承思想也是减少代码重复的一种方式。

HOC 是在组件化的基础上进行更进一步的代码复用,因为在各组件之间可能会使用相同的代码逻辑,将这些相同的代码逻辑抽离出来,放到高阶组件中进行复用。

2. 如何使用 HOC

在了解了 HOC 的诞生原因后,那么应该如何使用 HOC 呢?请时刻牢记一句话:HOC 本身是一个接收组件为参数并返回一个新组件的函数,不是一个组件

那么我们知道 HOC 是返回一个新组件,因此在 HOC 函数内肯定有 return new Component 的语句,那么旧的组件如何和新组件产生关联呢?答案就是在新组件中使用旧组件。

假如组件 A 和组件 B 都有读取浏览器本地存储中 test 属性值的需求,为了实现读取本地存储数据代码的复用,下面就创建一个简单的 HOC 高阶组件。

index.js

  1. localStorage.setItem('test', '我是 test')

withTest.js

  1. import React, {useState} from 'react';
  2. function withTest(OldComponent) {
  3. return function (props) {
  4. const [test, setTest] = useState(localStorage.getItem('test'))
  5. return (
  6. <OldComponent test={test} {...props}/>
  7. )
  8. }
  9. }
  10. export default withTest

A.js

  1. import React from 'react';
  2. import withTest from './withTest';
  3. function A(props) {
  4. return (
  5. <div>
  6. 我是 A 组件
  7. 我拿到的 test 为:{props.test}
  8. </div>
  9. )
  10. }
  11. export default withTest(A)

B.js

  1. import React from 'react';
  2. import withTest from './withTest';
  3. function B(props) {
  4. return (
  5. <div>
  6. 我是 B 组件
  7. 我拿到的 test 为:{props.test}
  8. </div>
  9. )
  10. }
  11. export default withTest(B)

App.js

  1. import React from 'react';
  2. import WithTestA from './A';
  3. import WithTestB from './B'
  4. function App() {
  5. return (
  6. <div className="App">
  7. 我是APP
  8. <WithTestA/>
  9. <WithTestB/>
  10. </div>
  11. );
  12. }
  13. export default App;

可以看到,在 HOC 高阶组件中,复用的代码逻辑是定义在新创建的组件中的,新组件中使用旧组件作为子组件时,通过 prop 的方式传递给子组件,子组件就可以拿到对应的数据。

我们在使用时也是使用的 HOC 返回后的新组件,新组件是包含了代码逻辑的旧组件。因此新组件就是包裹着旧组件的一个容器,这个容器中有对应的代码逻辑,其得到的数据通过 prop 的方式传递为旧组件。

以上就是 HOC 的简单应用。

3. HOC 带参数

HOC 是一个函数,除了可以接收一个组件外,当然可以接收其他的数据,接收的数据也可以传递给旧组件,如下

withTest.js

  1. import React, {useState} from 'react';
  2. function withTest(OldComponent, args) {
  3. return function (props) {
  4. const [test, setTest] = useState(localStorage.getItem('test'))
  5. return (
  6. <OldComponent test={test} {...props} args={args}/>
  7. )
  8. }
  9. }
  10. export default withTest

A.js

  1. import React from 'react';
  2. import withTest from './withTest';
  3. function A(props) {
  4. return (
  5. <div>
  6. 我是 A 组件
  7. 我拿到的 test 为:{props.test}
  8. 我拿到的 args 为:{props.args}
  9. </div>
  10. )
  11. }
  12. export default withTest(A, 'a')

4. connect 将参数抽离

connect 是一个返回高阶组件的高阶函数!

React-Redux 中的 connect 函数采用的方式是将 HOC 做成一个 Component => Component 的单参数 HOC,将从函数传参过来的数据传递到了第一层的函数中。

单参数 HOC 的好处就是便于组合 compose 到一起。

5. 高阶组件的注意事项

5.1 不要在 render 方法中使用 HOC

5.2 务必复制静态方法

5.3 Refs 不会被转发

参考链接

高阶组件(Higher-Order Components)
高阶组件