Реакция - вызов обернутого обратного вызова компонента из функции более высокого порядка - PullRequest
0 голосов
/ 12 октября 2018

У меня есть функция высшего порядка, которая упаковывает вызовы службы.Данные передаются по обратному вызову, который я должен передать упакованным компонентам.В настоящее время я написал код ниже, где ребенок присваивает 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);

1 Ответ

0 голосов
/ 12 октября 2018

Этот обернутый компонент должен знать, что 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 следует сделать более обобщенным для взаимодействия с обернутым компонентом через реквизиты, т.е. зарегистрировать обратный вызов:

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уже навязано рамками.

...