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
3 Réponses :
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> ); }
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>
Je t'ai eu! C'est la réponse claire à laquelle je m'attendais.
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 }); } } ); }