首页 > 解决方案 > 在父componentDidMount之后在React子中执行代码

问题描述

我将 axios 用于 Web 请求,并为其创建了一个拦截器,以显示所有错误消息的烤面包机。

我正在使用 react-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 调用都会触发 toast 消息。

我的问题如下。如果我在调用之前尝试使用 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);

一种解决方法是使用 Main 的构造函数(或 componentWillMoount)来注册拦截器,但这不会支持异步渲染,因为这些方法不能保证只运行一次。

我可以以某种方式更改 2 个componentDidMount调用的顺序或为此使用任何其他生命周期方法吗?

标签: reactjsaxioslifecycle

解决方案


我不确定是什么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标志传递给孩子并将他们的逻辑componentDidMountcomponentDidUpdate

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

推荐阅读