Ошибка "Не удалось обновить во время существующего перехода состояния" в React
Я пытаюсь сделать шаг 15 этого учебника ReactJS: React.js Введение для людей, которые знают, что достаточно JQuery для получения информации
Автор рекомендует следующее:
overflowAlert: function() {
if (this.remainingCharacters() < 0) {
return (
<div className="alert alert-warning">
<strong>Oops! Too Long:</strong>
</div>
);
} else {
return "";
}
},
render() {
...
{ this.overflowAlert() }
...
}
Я пробовал сделать следующее (что выглядит хорошо для меня):
// initialized "warnText" inside "getInitialState"
overflowAlert: function() {
if (this.remainingCharacters() < 0) {
this.setState({ warnText: "Oops! Too Long:" });
} else {
this.setState({ warnText: "" });
}
},
render() {
...
{ this.overflowAlert() }
<div>{this.state.warnText}</div>
...
}
И я получил следующую ошибку в консоли в Chrome Dev Tools:
Невозможно обновить во время существующего перехода состояния (например, внутри render
или другого конструктора компонента). Методы визуализации должны быть чистая функция реквизита и состояния; побочные эффекты конструктора anti-pattern, но может быть перенесен на componentWillMount
.
Здесь JSbin demo. Почему мое решение не работает и что означает эта ошибка?
Ответы
Ответ 1
Ваше решение работает, потому что оно не имеет смысла логически. Ошибка, которую вы получаете, может быть немного туманной, поэтому позвольте мне сломать ее. В первой строке указано:
Невозможно обновить во время существующего перехода состояния (например, в рендере или другом конструкторе компонента).
Когда обновляется состояние компонента React, компонент переизлучается в DOM. В этом случае возникает ошибка, потому что вы пытаетесь вызвать overflowAlert
внутри render
, который вызывает setState
. Это означает, что вы пытаетесь обновить состояние в рендере, которое будет затем вызывать рендеринг и overflowAlert
, а также обновить состояние и повторно выполнить рендеринг и т.д., Что приведет к бесконечному циклу. Ошибка сообщает вам, что вы пытаетесь обновить состояние в результате обновления состояния в первую очередь, что приводит к циклу. Вот почему это не разрешено.
Вместо этого возьмите другой подход и вспомните, что вы пытаетесь выполнить. Вы пытаетесь дать предупреждение пользователю при вводе текста? Если это случай, установите overflowAlert
в качестве обработчика события ввода. Таким образом, состояние будет обновляться, когда произойдет событие ввода, и компонент будет перезаписан.
Ответ 2
Вместо выполнения какой-либо задачи, связанной с компонентом в методе рендеринга, сделайте это после обновления компонента
В этом случае переход с экрана Splash на другой экран выполняется только после вызова метода componentDidMount.
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Button,
Image,
} from 'react-native';
let timeoutid;
export default class Splash extends Component {
static navigationOptions = {
navbarHidden: true,
tabBarHidden: true,
};
constructor(props) {
super(props)
this.state = { navigatenow: false };
}
componentDidMount() {
timeoutid=setTimeout(() => {
this.setState({ navigatenow: true });
}, 5000);
}
componentWillUnmount(){
clearTimeout(timeoutid);
}
componentDidUpdate(){
const { navigate,goBack } = this.props.navigation;
if (this.state.navigatenow == true) {
navigate('Main');
}
}
render() {
//instead of writing this code in render write this code in
componenetDidUdpate method
/* const { navigate,goBack } = this.props.navigation;
if (this.state.navigatenow == true) {
navigate('Main');
}*/
return (
<Image style={{
flex: 1, width: null,
height: null,
resizeMode: 'cover'
}} source={require('./login.png')}>
</Image>
);
}
}
Ответ 3
Убедитесь, что вы используете правильное выражение. Например, используя:
<View onPress={this.props.navigation.navigate('Page1')} />
отличается от
<View onPress={ () => this.props.navigation.navigate('Page1')} />
или
<View onPress={ () => {
this.props.navigation.navigate('Page1')
}} />
Два последних выше - выражение функции, первое - нет. Убедитесь, что вы передаете функциональный объект в выражение функции () => {}