灏天阁

React 高阶组件

· Yin灏

高阶组件

High Order Component

  1. HOC 是一种高级的设计模式
  2. HOC 是一个函数,接收一个组件参数,返回一个新组件
  3. 普通组件返回的是 UIHOC 返回的是一个新组件
  4. HOC 不能修改参数组件,只能传入组件所需的 props
  5. HOC 是一个没有副作用的纯函数
  6. HOC 除了必须填入被包裹的组件参数外,其他参数根据需求增加
  7. HOC 不关心数据如何使用,包裹组件不关心数据从哪里来
  8. HOC 和包裹组件唯一直接的契合点就是 props

HOC 更加关注逻辑和状态的管理,参数组件的逻辑与状态订阅; 参数组件基本只需关注视图的渲染;

function fetchListData(field) {
  return new Promise((resolve, reject) => {
    resolve({
      data: [
        {
          name: "zs",
          age: 12,
          score: 44,
        },
        {
          name: "ls",
          age: 12,
          score: 44,
        },
        {
          name: "ww",
          age: 12,
          score: 44,
        },
      ],
    });
  });
}

function listHoc(WrapperComponent, fetchListData) {
  return class extends React.Component {
    state = {
      listData: [],
    };
    async componentDidMount() {
      const result = await fetchListData(this.props.field);

      this.setState({
        listData: result.data,
      });
    }

    removeStd(name) {
      this.setState({
        listData: this.state.listData.filter((item) => item.name !== name),
      });
    }

    render() {
      return (
        <WrapperComponent
          data={this.state.listData}
          removeStd={this.removeStd.bind(this)}
        />
      );
    }
  };
}

class StudentList extends React.Component {
  render() {
    return (
      <table border="1">
        <thead>
          <tr>
            <th>Name</th>
            <th>Age</th>
            <th>Score</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          {this.props.data.map((item, index) => (
            <tr>
              <td>{item.name}</td>
              <td>{item.age}</td>
              <td>{item.score}</td>
              <td onClick={() => this.props.removeStd(item.name)}>删除</td>
            </tr>
          ))}
        </tbody>
      </table>
    );
  }
}

const StudentListHoc = listHoc(StudentList, fetchListData);

class App extends React.Component {
  render() {
    return <StudentListHoc field="student" />;
  }
}

ReactDOM.render(<App />, document.querySelector("#app"));
function InputHoc(WrapperComp) {
  // 会导致原组件声明周期中对应的函数不会执行,相当于重写
  // 不能这样修改,可能会导致组件内部的逻辑失效
  // WrapperComp.prototype.componentDidUpdate = function () {
  //   console.log("Input Hoc1");
  // };

  class InputComponent extends React.Component {
    state = {
      value: "",
    };
    // 这里和上面的重写不冲突
    // 可以在这里重写函数,与原组件内部逻辑不冲突,用作对原组件逻辑的扩展
    componentDidUpdate() {
      console.log("Input Hoc2");
    }

    chgInput(e) {
      this.setState({
        value: e.target.value,
      });
    }
    render() {
      const { a, ...props } = this.props;

      return (
        <WrapperComp
          value={this.state.value}
          chgInput={this.chgInput.bind(this)}
          {...props}
        />
      );
    }
  }
  // 可以改变别名
  InputComponent.displayName = "InputHoc";

  return InputComponent;
}

class MyInput extends React.Component {
  componentDidUpdate() {
    console.log("MyInput");
  }

  render() {
    return (
      <div>
        <p>总计: {this.props.b + this.props.c}</p>
        <p>
          <input
            type="text"
            defaultValue={this.props.value}
            onChange={this.props.chgInput}
          />
        </p>
        <p>{this.props.value}</p>
      </div>
    );
  }
}

const MyInputHoc = InputHoc(MyInput);

class App extends React.Component {
  state = {
    a: 1,
    b: 2,
    c: 3,
  };

  render() {
    return <MyInputHoc {...this.state} />;
  }
}
ReactDOM.render(<App />, document.querySelector("#app"));

- Book Lists -