web-dev-qa-db-fra.com

Erreur "Impossible de mettre à jour pendant une transition d'état existante" dans React

J'essaie de faire l'étape 15 de ce didacticiel ReactJS: React.js Introduction Pour les personnes qui en savent assez sur jQuery pour obtenir

L'auteur recommande ce qui suit:

overflowAlert: function() {
  if (this.remainingCharacters() < 0) {
    return (
      <div className="alert alert-warning">
        <strong>Oops! Too Long:</strong>
      </div>
    );
  } else {
    return "";
  }
},

render() {
  ...

  { this.overflowAlert() }

  ...
}

J'ai essayé de faire ce qui suit (ce qui me semble bien):

// 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>

  ...
}

Et j'ai reçu l'erreur suivante dans la console dans Chrome Dev Tools:

Mise à jour impossible lors d'une transition d'état existante (telle que dans render ou le constructeur d'un autre composant). Les méthodes de rendu doivent être une fonction pure d'accessoires et d'état; Les effets secondaires du constructeur sont un anti-pattern, mais peut être déplacé à componentWillMount.

Voici une démo de JSbin . Pourquoi ma solution ne fonctionne-t-elle pas et que signifie cette erreur?

11
thanks_in_advance

Votre solution fonctionne, car elle n’a aucun sens logique. L'erreur que vous recevez peut être un peu vague, alors laissez-moi la décomposer. La première ligne indique:

Mise à jour impossible lors d'une transition d'état existante (par exemple, dans le rendu ou le constructeur d'un autre composant).

Chaque fois que l'état d'un composant React est mis à jour, le composant est rendu au DOM. Dans ce cas, il y a une erreur car vous essayez d'appeler overflowAlert dans render, qui appelle setState. Cela signifie que vous essayez de mettre à jour un état dans render qui appellera ensuite render et overflowAlert et que vous mettrez à jour un état, puis appelez render, etc. conduisant à une boucle infinie. L'erreur vous indique que vous essayez de mettre à jour l'état en conséquence, ce qui a entraîné une boucle. C'est pourquoi cela n'est pas autorisé.

Au lieu de cela, prenez une autre approche et rappelez-vous ce que vous essayez d'accomplir. Essayez-vous d'avertir l'utilisateur lorsqu'il saisit du texte? Si tel est le cas, définissez overflowAlert en tant que gestionnaire d'événements d'une entrée. De cette façon, l'état sera mis à jour lorsqu'un événement d'entrée se produit et le composant sera rendu à nouveau.

23
Li357

Assurez-vous que vous utilisez l'expression correcte. Par exemple, en utilisant:

<View onPress={this.props.navigation.navigate('Page1')} />

est différent avec

<View onPress={ () => this.props.navigation.navigate('Page1')} />

ou 

<View onPress={ () => {
    this.props.navigation.navigate('Page1')
}} />

Les deux derniers ci-dessus sont l'expression de la fonction, la première ne l'est pas. Assurez-vous que vous passez l'objet de fonction à l'expression de fonction () => {}

1
azwar_akbar

Au lieu d'effectuer une tâche liée à un composant dans la méthode de rendu, effectuez-le après la mise à jour du composant.

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>
);

  }
}
0
Basheer Kohli