【问题标题】:React - Call wrapped component callback from higher order functionReact - 从高阶函数调用包装的组件回调
【发布时间】:2018-10-12 07:09:52
【问题描述】:

我有一个包装服务调用的高阶函数。数据通过回调流式传输,我必须将其传递给包装的组件。我目前已经编写了下面的代码,其中孩子将 handleChange 分配给 HOC 传递的空对象。包装的组件是一个常规的 JS 网格,因此我必须调用 api 来添加数据,而不是将其作为道具传递。 有没有更清洁的方法?

    function withSubscription(WrappedComponent) {     
    return class extends React.Component {
      constructor(props) {
        super(props);       
        this.handler = {};
      }

      componentDidMount() { 
        DataSource.addChangeListener(this.handleChange);
      }

      componentWillUnmount() {
        DataSource.removeChangeListener(this.handleChange);
      }

      handleChange(row) {
        if (typeof this.handler.handleChange === "function") {
            this.handler.handleChange(row);
        }
      }

      render() { 
        return <WrappedComponent serviceHandler={this.handler} {...this.props} />;
      }
    };
  }

  class MyGrid extends React.Component {
     constructor(props) {
         super(props);
         if (props.serviceHandler !== undefined) {
             props.serviceHandler.handleChange = this.handleChange.bind(this);
         }

         this.onReady = this.onReady.bind(this);
     }

     onReady(evt) {
         this.gridApi = evt.api;
     }

     handleChange(row) {
        this.gridApi.addRow(row);
     }

     render() { 
        return <NonReactGrid onReady={this.onReady} />;
      }

  }

  const GridWithSubscription = withSubscription(MyGrid);

【问题讨论】:

    标签: reactjs higher-order-functions


    【解决方案1】:

    那个被包裹的组件应该知道handler.handleChange看起来很别扭。

    如果withSubscription 可以被限制为仅与有状态组件一起使用,则组件可能会暴露changeHandler 钩子:

    function withSubscription(WrappedComponent) {
      return class extends React.Component {
        ...
        wrappedRef = React.createRef();
    
        handleChange = (row) => {
          if (typeof this.wrappedRef.current.changeHandler === "function") {
            this.wrappedRef.current.changeHandler(row);
          }
        }
    
        render() { 
          return <WrappedComponent ref={this.wrappedRef}{...this.props} />;
        }
      };
    }
    
    class MyGrid extends React.Component {
      changeHandler = (row) => {
        ...
      }
    }
    
    const GridWithSubscription = withSubscription(MyGrid);
    

    要使用有状态和无状态组件,withSubscription 应该更通用,以便通过 props 与包装组件交互,即注册回调:

    function withSubscription(WrappedComponent) {
      return class extends React.Component {
        handleChange = (row) => {
          if (typeof this.changeHandler === "function") {
            this.changeHandler(row);
          }
        }
    
        registerChangeHandler = (cb) => {
          this.changeHandler = cb;
        }
    
        render() { 
          return <WrappedComponent
            registerChangeHandler={this.registerChangeHandler}
            {...this.props}
          />;
        }
      };
    }
    
    class MyGrid extends React.Component {
      constructor(props) {
        super(props);
        props.registerChangeHandler(this.changeHandler);
      }
      changeHandler = (row) => {
        ...
      }
    }
    

    如果应用程序已经使用了某种形式的事件发射器,例如 RxJS 主题,则可以使用它们而不是 handler.handleChange 在父子之间进行交互:

    function withSubscription(WrappedComponent) {
      return class extends React.Component {
        changeEmitter = new Rx.Subject();
    
        handleChange = (row) => {
          this.changeEmitter.next(row);
        }
    
        render() { 
          return <WrappedComponent
            changeEmitter={this.changeEmitter}
            {...this.props}
          />;
        }
      };
    }
    
    class MyGrid extends React.Component {
      constructor(props) {
        super(props);
        this.props.changeEmitter.subscribe(this.changeHandler);
      }
    
      componentWillUnmount() {
        this.props.changeEmitter.unsubscribe();
      }
    
      changeHandler = (row) => {
        ...
      }
    }
    

    为此目的传递主题/事件发射器在 Angular 中很常见,因为框架已经强加了对 RxJS 的依赖。

    【讨论】:

      猜你喜欢
      • 2020-01-27
      • 2018-02-25
      • 2019-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多