Правильное место для обновления состояния - React JS - PullRequest
1 голос
/ 17 июня 2020

Я создаю простой компонент слайдера в React JS. У меня есть три кнопки Restart, Previous, Next. Щелчок по предыдущему уменьшит текущее состояние на 1 и будет продолжаться до тех пор, пока текущее состояние не станет равным 0. Кроме того, следующая кнопка будет увеличивать состояние до тех пор, пока оно не станет равным slides.length-1. Ползунок у меня работает нормально, проблема в том, что когда последний слайд приближается, кнопка «Далее» все еще активна, но когда я нажимаю на нее, она отключается. Ожидаемое поведение: когда отображается последний слайд, кнопка должна быть отключена, и дополнительный щелчок не требуется. Та же проблема с предыдущей кнопкой.

Вы можете проверить поведение здесь: https://codesandbox.io/s/react-live-sandbox-krfjk

Я уверен, что есть проблема с обновлением состояния, возможно, я обновляю его не в том месте, вот что не волнует меня.

Ответы [ 3 ]

1 голос
/ 17 июня 2020

Внутри вашего nextHandler() измените setState на это:

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

Учитывая простоту вашего приложения, вам не нужно prevState - вам также не нужно определять каждое состояние в поле возврата (response будет неявно заполнить их как последнее значение):

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

Причина, по которой это не сработало, заключается в том, что вы использовали следующее, чтобы проверить, должна ли кнопка быть отключена:

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

prevState будет на 1 счет меньше того, что вы намереваетесь. Для этого вам нужно использовать текущее состояние. Другим исправлением было бы изменить его на:

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

Вы можете применить аналогичное исправление к prevHandler().

1 голос
/ 17 июня 2020

Проблема в вашем коде заключается в том, что вы не обновляете currentSlide, прежде чем проверяете, должна ли быть отключена предыдущая или следующая кнопка.

При нажатии любой кнопки сначала обновите currentSlide, затем проверьте, какая кнопка должна быть включена или отключена.

nextHandler функция должна выглядеть так

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

и prevHandler должны выглядеть так

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

Edit react-live-sandbox

1 голос
/ 17 июня 2020

У вас такое же поведение при нажатии кнопки «prev». Может быть проще получить отключенное состояние, чем пытаться вычислить его и сохранить в состоянии.

Слайды. 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>
  );
}

Edit quote slider prev/next example

...