#javascript #reactjs #web
#javascript #reactjs #веб
Вопрос:
У меня есть 3 подразделения. У каждого будет активный класс, когда я нажму на определенную кнопку. У каждого из них есть переменная состояния всякий раз, когда это правда, я добавляю className= ‘active’ в подключенный к нему div:
Когда я нажимаю на кнопку, состояние изменяется, но div не активирует класс
async activeLang(e) {
let lang = e.target.getAttribute('lang');
for (const key in this.state.status) {
if (key === lang) {
await this.setState(state => {
state.status[key] = true
})
}else{
await this.setState(state => {
state.status[key] = false
})
}
}
console.log(this.state.status);
}
когда я меняю функцию на эту, она работает:
activeLang(e) {
let lang = e.target.getAttribute('lang');
this.setState({
status:{
en: false,
ar: false,
fr: false,
}
})
this.setState(state => {
state.status[lang] = true
})
console.log(this.state.status);
}
================================================
<ul>
<li lang="en" onClick={this.activeLang} className={this.state.status.en ? 'active' : '' }>EN</li>
<li lang="ar" onClick={this.activeLang} className={this.state.status.ar ? 'active' : ''}>AR</li>
<li lang="fr" onClick={this.activeLang} className={this.state.status.fr ? 'active' : ''}>FR</li>
</ul>
================================================
<div className={this.state.status.en ? 'to-input en active' : 'to-input en'}>
<input required type='text' onKeyUp={this.onInputChange} />
<label title='Category name' placeholder='Ex. Business Cards'></label>
</div>
<div className={this.state.status.ar ? 'to-input ar active' : 'to-input ar'}>
<input required type='text' onKeyUp={this.onInputChange} />
<label title='اسم الفئة' placeholder='مثال: كروت العمل'></label>
</div>
<div className={this.state.status.fr ? 'to-input fr active' : 'to-input fr'}>
<input required type='text' onKeyUp={this.onInputChange} />
<label title='Nom de catégorie' placeholder='Ex. Cartes de visite'></label>
</div>
Комментарии:
1. Вы не можете использовать setState в цикле. setState не выполняется немедленно, он получает расписания и — и это важная часть — только последний setState «выигрывает» к моменту фактического запуска обновления состояния. Поэтому никогда не используйте setState внутри цикла. Выполняйте преобразования данных и всю остальную работу, а затем вызывайте setState только один раз с новым состоянием. В этом суть setState: он обновляет ваш компонент из его предыдущего состояния в его новое состояние. Не используйте его ни для чего промежуточного.
Ответ №1:
Не делайте этого в цикле. Просто вызовите его один раз:
const lang = e.target.getAttribute('lang');
this.setState(state => ({
...state,
status: Object.keys(state.status).reduce((acc,key) => ({
...acc,
[key]:state.status[key] === lang // set all statuses to false except for `lang`
}),{});
});
Редактировать:
Кроме того, setState
не возвращает обещание, вы не можете await
этого сделать. Он принимает обратный вызов, но это не лучшее решение здесь (см. Выше).
Вы никогда не должны вызывать setState
цикл, произойдет путаница.
РЕДАКТИРОВАТЬ #2:
Судя по всему, у меня есть лучшее решение для вашего состояния. Только один язык может иметь статус active одновременно, поэтому вам не нужно status
— все, что вам нужно, это знать, что такое активированный язык, следовательно:
const state = { activatedLang: 'en' } // or 'fr' or 'ar'
Тогда вы можете просто сделать это:
this.setState({ activatedLang: e.target.getAttribute('lang') });
Комментарии:
1. Ваш ответ действительно хорош. Я не знал об операторе 3 dots, я просто искал его, и это очень поможет. Спасибо.