Я впервые делаю автоматы с конечным состоянием. Я попытался создать программу стоп-сигнала, в которой, если вы нажмете кнопку, свет изменится один раз, начиная с зеленого, затем на желтый, если щелкнуть снова, затем на красный, прежде чем снова зациклиться. Мне удалось заставить его работать, за исключением одной маленькой ошибки. Его нужно дважды щелкнуть, прежде чем экран обновится, и я действительно не знаю, как это исправить.
Я заметил на своей консоли, что 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 :)
почему вы используете currentLightState в функции перехода? Почему бы просто не использовать this.state.light непосредственно в lightMaching[this.state.light][action] вот так?
Основная причина, по которой я использую currentLightState, заключается в том, что, поскольку я видел другие примеры людей, использующих конечные автоматы для создания подобных программ, все они делали что-то подобное. В результате я подумал, что это правильный путь =/
@Jr194! Добро пожаловать в переполнение стека! Я только что написал вам довольно подробный ответ на ваш вопрос о вашем коде и о том, почему некоторые вещи не работали.





Добро пожаловать на доски 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>
}
}
Вау спасибо за обстоятельный ответ! Я новичок в реагирующих и конечных машинах, поэтому, честно говоря, я был очень сбит с толку после просмотра статей и примеров того, как сделать конечную машину в реакции. Посмотрев на вашу собственную версию кода, я понял, как я все усложнял. Ваш ответ немного прояснил мое замешательство :)
@ Jr194, пожалуйста! Я рад, что это помогло вам :). React — настоящий зверь, и вы обязательно станете лучше, если будете использовать его больше. Если вы обнаружили, что это решение вашей проблемы, отметьте его как ответ, чтобы кто-то в будущем мог обратиться к нему, когда у него возникнет тот же вопрос.
Можете ли вы опубликовать свою функцию HandleClick? Было бы полезно все же увидеть все это.