1
votes

Le bon endroit pour mettre à jour un état - React JS

Je crée un composant de curseur simple dans React JS. J'ai trois boutons Redémarrer , Précédent , Suivant . Cliquer sur le précédent décrémentera l'état actuel de 1 et continuera jusqu'à ce que l'état actuel soit égal à 0. De plus, le bouton suivant incrémentera l'état jusqu'à ce qu'il soit égal à slides.length-1 . Le curseur fonctionne bien pour moi, le problème est que lorsque la dernière diapositive approche, le bouton «Suivant» est toujours activé, mais lorsque je clique dessus, il devient alors désactivé. Le comportement attendu est que lorsque la dernière diapositive est rendue, le bouton doit être désactivé et aucun clic supplémentaire ne doit être requis. Le même problème est avec le bouton précédent.

Vous pouvez vérifier le comportement ici: https://codesandbox.io/s/ react-live-sandbox-krfjk


0 commentaires

3 Réponses :


1
votes

Vous avez également le même comportement lorsque vous cliquez sur le bouton "Précédent". Il peut être plus facile de dériver l'état désactivé que d'essayer de le calculer et de le stocker dans l'état.

Fonction de rendu de Slides.js

render() {
  const { slides } = this.props;
  return (
    <div>
      <div id="navigation">
        <button
          data-testid="button-restart"
          onClick={this.resandler}
          data-testid="button-restart">
          Restart
        </button>
        <button
          data-testid="button-prev"
          onClick={this.prevHandler}
          data-testid="button-prev"
          // if current slide is 0, there is no previous
          disabled={this.state.currentSlide === 0}>
          Prev
        </button>
        <button
          data-testid="button-next"
          onClick={this.nextHandler}
          data-testid="button-next"
          // if current slide is slides.length - 1, there is no next
          disabled={this.state.currentSlide === this.props.slides.length - 1}>
          Next
        </button>
      </div>
      {slides.map((slide, i) => {
        return i === this.state.currentSlide ? (
          <div id="slide" key={slide + i}>
            <h1 data-testid="title">{slide.title}</h1>
            <p data-testid="text">{slide.text}</p>
          </div>
        ) : null;
      })}
    </div>
  );
}

 Modifier le curseur de citation précédent / exemple suivant


0 commentaires

1
votes

Dans votre nextHandler () changez le setState en ceci:

prevState.currentSlide + 1 === this.props.slides.length - 1

Compte tenu de la simplicité de votre application, vous n'avez pas besoin de prevState - Vous il n'est pas non plus nécessaire de définir tous les champs d'état dans le retour (react les remplira implicitement comme leur dernière valeur):

prevState.currentSlide === this.props.slides.length - 1

La raison pour laquelle cela n'a pas fonctionné est que vous utilisiez ce qui suit pour vérifier si le bouton doit être désactivé:

// This can be just prevState => since you aren't using props
this.setState((prevState, props) => {
  if (prevState.currentSlide < this.props.slides.length - 1) {
    return {
      currentSlide: prevState.currentSlide + 1,
      prevDisabled: false, 
    };
  } else if (prevState.currentSlide === this.props.slides.length - 1) { // Issue is here
    return {
      nextDisabled: true,
      prevDisabled: false, // Don't need to keep defining this
    };
  }
});

Le prevState sera de 1 compte derrière ce que vous avez l'intention. Vous devez utiliser l'état actuel pour ce faire. Un autre correctif serait donc de le changer en:

this.setState({
      currentSlide: this.state.currentSlide + 1,
      nextDisabled: this.state.currentSlide + 1 === this.props.slides.length -  1,
      prevDisabled: false,
});

Vous pouvez appliquer un correctif similaire à prevHandler () .

p>


1 commentaires

Je t'ai eu! C'est la réponse claire à laquelle je m'attendais.



1
votes

Le problème dans votre code est que vous ne mettez pas à jour le currentSlide avant de vérifier si le bouton précédent ou suivant doit être désactivé.

Lorsque vous appuyez sur un bouton, mettez d'abord à jour le currentSlide puis vérifiez quel bouton doit être activé ou désactivé.

La fonction nextHandler devrait ressembler à ceci

prevHandler() {
    this.setState(
      prevState => ({ currentSlide: --prevState.currentSlide}),
      () => {
        if (this.state.currentSlide === 0) {
          this.setState({ nextDisabled: false, prevDisabled: true });
        } 
      }
    );
}

et prevHandler devrait être comme ceci

nextHandler() {
    this.setState(
        prevState => ({ currentSlide: ++prevState.currentSlide}),
        () => {
          if (this.state.currentSlide < this.props.slides.length - 1) {
            this.setState({ prevDisabled: false });
          } else {
            this.setState({ nextDisabled: true });
          }
        }
    );
} 

 Modifier react-live-sandbox


0 commentaires