Выполнить код в дочерних элементах React после родительского componentDidMount - PullRequest
0 голосов
/ 25 марта 2019

Я использую axios для веб-запросов и создал перехватчик, чтобы он показывал тостер для всех сообщений об ошибках.

Я использую реагирование-intl для переводов, и общее сообщение об ошибке, присутствующее в перехватчике, переведено, поэтому я привязываю перехватчик к жизненному циклу моего приложения:

class Main extends React.Component {
  componentDidMount () {

    // addToastInterceptor calls back for a message that can be evaluated dynamically
    // otherwise it uses axios.interceptors.response.use(...)
    this.interceptor = addToastInterceptor((e) =>
      this.props.intl.formatMessage({
        id: 'applicationForm.basic.errorMessage'
      }, {
        technicalMessage: e.message
      }));
  }

  componentWillUnmount () {
    // the interceptor handle is removed when the component unmounts
    removeToastInterceptor(this.interceptor);
  }

  render() {
    // any number of child component in any depth
  }
}

// The intl provider must exist in a wrapper component
export default injectIntl(Main);

Таким образом, пока компонент Main монтируется, любой вызов axios, который получает ответ об ошибке, вызовет всплывающее сообщение.

Моя проблема в следующем. Если я попытаюсь позвонить с помощью axios до вызова Main.componentDidMount, сообщение не появится.

Если я сделаю вызов в componentDidMount компонента-потомка, он не покажет сообщение:

// This component dispatches a redux call that uses axios.get internally
class SomeChild extends React.Component {
  componentDidMount () {
    // this is 
    this.props.getCountriesAction();
  }
}

const mapStateToProps = state => ({
  countries: state.boarding.countries,
});

const mapDispatchToProps = dispatch => bindActionCreators({
  getCountriesAction: getCountries,
}, dispatch);

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(SomeChild);

Одним из обходных путей может быть использование конструктора (или componentWillMoount) из Main для регистрации перехватчика, но это не выдержит асинхронного рендеринга, поскольку эти методы не гарантированно будут выполняться только один раз.

Могу ли я как-то изменить порядок вызовов 2 componentDidMount или использовать для этого другие методы жизненного цикла?

1 Ответ

0 голосов
/ 25 марта 2019

Я не уверен, что делает addToastInterceptor. Я думаю, что это хорошо, чтобы назвать это внутри constructor. В случае, если некоторая работа действительно должна быть сделана внутри componentDidMount перед методами жизненного цикла детей, вы можете использовать флаг, чтобы задержать рендеринг детей, пока все не будет готово:

class Main extends React.Component {
  state = {isReady: false}

  componentDidMount () {

    // addToastInterceptor calls back for a message that can be evaluated dynamically
    // otherwise it uses axios.interceptors.response.use(...)
    this.interceptor = addToastInterceptor((e) =>
      this.props.intl.formatMessage({
        id: 'applicationForm.basic.errorMessage'
      }, {
        technicalMessage: e.message
      }));

    this.setState({isReady: true});
  }

  render {
    if (!this.state.isReady) return null;
    ...
  }
}

Если работа внутри componentDidMount занимает много времени, и вы хотите что-то визуализировать, вы можете передать детям флаг isReady и переместить их логику с componentDidMount на componentDidUpdate:

componentDidUpdate(prevProps) {
  if (this.props.isReady && this.props.isReady !== prevProps.isReady) {
    /* child's logic from componentDidMount */
  }
}
...