Я использую axios для веб-запросов и создал для него перехватчик, чтобы показывать тостер для всех сообщений об ошибках.
Я использую 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, получивший ответ об ошибке, вызовет всплывающее сообщение.
Моя проблема заключается в следующем. Если я попытаюсь вызвать с помощью 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 или использовать для этого какие-либо другие методы жизненного цикла?





Я не уверен, что делает 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 */
}
}
Тогда вы должны использовать только первую часть решения и return null или какой-нибудь индикатор занятости вместо дочерних элементов на первом рендере.
Я действительно не хочу, чтобы явные параметры передавались, тем более что дочерний элемент не обязательно является прямым дочерним элементом, а является потомком. Я мог бы использовать контекст, но это было бы немного тяжело для этого. Я бы с удовольствием использовал ctor, но это не гарантирует, что он запустится только один раз, и потенциально может регистрировать один и тот же перехватчик много раз.