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

Я впервые делаю конечные автоматы. Я попытался создать программу типа "стоп-сигнал", в которой, если вы нажмете кнопку, индикатор изменится один раз, начиная с зеленого, затем с желтого, если щелкнуть снова, а затем с красным, перед повторным циклом. Мне удалось заставить его работать, за исключением одного небольшого бага. Его нужно дважды щелкнуть перед обновлением экрана, и я не знаю, как это исправить.

Я заметил на своей консоли, что currentLightState изменяется, когда я нажимаю на него, но возвращается к предыдущему цвету при первом щелчке. Я понял, что это потому, что он не синхронизирован с моим состоянием. Однако, когда я пытаюсь поместить currentLightState внутри класса и назначить this.state.light, currentLightState становится неопределенным. Я попытался добавить.bind(this) в конце this.state.light, но я просто получаю еще одну ошибку, говоря, что это не функция. Какие-либо предложения?

Я не опубликовал свою функцию обновления или функцию onHandleClick, поскольку она не имеет непосредственного отношения к currentLightState.

const lightMachine = {
  green:{
    LIGHT: 'yellow'
  },
  yellow:{
    LIGHT: 'red'
  },
  red:{
    LIGHT: 'green'
  }
}

// current location of currentLightState
let currentLightState = 'green';
class App extends React.Component{
    constructor(props){
        super(props);
        this.state = {
          light: 'green'    //initial value
        };
      }
    transition(state, action){
      // This is where my currentLightState messes up the first run 
      currentLightState = this.state.light

      const nextLightState =  lightMachine[currentLightState][action]
      this.setState({light: nextLightState}) 
    }
    render(){

        return(
            <div>
              <button onClick={this.onHandleClick.bind(this)}>
                change the Light!
              </button>
                {currentLightState}
            </div>
            );
        }
    }

РЕДАКТИРОВАТЬ: Вот моя функция onHandleClick:)

    onHandleClick(){
      this.update(currentLightState)

    };

Кроме того, я думаю, что я решил свою проблему, просто заменив currentLightState в функции рендеринга this.state.light.

ИДК, если это законное исправление или нет, но, кажется, работает в настоящее время.

Было бы неплохо, если бы кто-то еще мог ответить, почему, когда вы помещаете currentLightState в класс и присваиваете ему state.light, он становится неопределенным. Это поможет расширить мои знания React:)

1 ответ

Решение

Добро пожаловать на доски Jr194!

По теме, думаю, будет полезно сохранить currentLight а также lightMachine как значения, управляемые состоянием вашего компонента. Это помогает гарантировать, что вся ваша логика находится в одном и том же контексте, избегая таких странных ошибок, как "бла-бла не определено".

Во-вторых, вы, похоже, определили несколько функций, которые действительно можно сузить до одной. update, onHandleClick а также transition кажется, все пытаются сделать то же самое.

Наконец, рассмотрите возможность реорганизации кода в вашем lightMachine быть немного более интуитивным, чтобы вы могли быстро перейти к следующему свету. Вы уже знаете, какой текущий цвет у родительского ключа, действительно ли им нужно, чтобы его объект содержал другой ключ с тем же значением?

Рассмотрим следующий код:

class App extends React.Component {
  state = {
    currentLight: "green",
    lightMachine: {
      green: {
        nextLight: "yellow"
      },
      yellow: {
        nextLight: "red"
      },
      red: {
        nextLight: "green"
      }
    }
  };

  transition = () => {
    const currentLight = this.state.currentLight;
    const nextLight = this.state.lightColors[currentLight].nextLight;
    this.setState({
      currentLight: nextLight
    });
  };
  render() {
    return (
      <div>
        <button onClick={this.transition}>Click Me</button>
        <div>{this.state.currentLight}</div>
      </div>
    );
  }
}

Это должно позволить вам быстро изменить свет, как и ожидалось. А вот и песочница: https://codesandbox.io/s/4x08ovyjp7

Дайте знать, если у вас появятся вопросы:)

Также относительно вашего вопроса о том, почему currentLightState выдает ошибку в вашем render когда вы положите его в класс. Это не проблема React, это проблема JavaScript.

Давайте рассмотрим несколько примеров:

const test= "hello"
class Example extends React.Component{
   state = {
       greeting: "woof"
   }
   render(){
     <div>{test}</div>
   }
}

Как вы знаете, это не даст нам никакой ошибки. Мы подключаемся к переменной, которая определена вне нашего класса, и это совершенно нормально.

Теперь давайте посмотрим на это

class Example extends React.Component{
   state = {
       greeting: "woof"
   }

   test = this.state.greeting

   render(){
     <div>{test}</div>
   }
}

Это дает нам ошибку. Почему, потому что в вашем методе рендеринга вы рассматриваете тест как переменную, а не так. В class объект, подобный тому, который вы написали, currentLightState и сейчас test рассматриваются как properties, а не переменные. Чтобы получить доступ к свойству внутри класса, вам нужно использовать "this"ключевое слово, то, что вы уже делали с this.update, this.handleOnClick и т. д., которые также являются свойствами.

Теперь мы знаем, что этот код будет работать.

class Example extends React.Component{
   state = {
       greeting: "woof"
   }

   test = this.state.greeting

   render(){
     <div>{this.test}</div>
   }
}
Другие вопросы по тегам