#javascript #reactjs #render #setstate
#javascript #reactjs #визуализация #setstate
Вопрос:
Я пытаюсь создать sidemenu, который имеет сворачиваемые параметры.
Ниже приведен мой код:
export default class CRSideMenu extends React.Component {
constructor(props) {
super(props);
this.state = {
fprActive: true
};
autoBind(this);
}
toggleFPR() {
console.log('Setting fprActive from ', this.state.fprActive, ' to ', !this.state.fprActive);
this.setState({
fprActive: !this.state.fprActive
});
}
render() {
console.log('render', this.state.fprActive);
return (
<ul className='list-group list-group-nav'>
<li>
<a
href='#'
className={classnames('list-group-item', this.state.fprActive amp;amp; 'active', 'has-subnav')}
onClick={this.toggleFPR} >
FPR
</a>
<ul className='list-group list-group-nav'>
<li>
<a href='' className='list-group-item'>FR</a>
</li>
</ul>
</li>
</ul>
);
}
}
Когда я распечатал this.state.fprActive
в методе render (), я вижу следующее:
- Изменение значения fprActive с true на false
- отображать false
- отображать true
Почему мой fprActive автоматически возвращается к «true», когда я нажимаю только один раз?
Комментарии:
1. Я предполагаю, что
autoBind
делаетtoggleFDR
привязку кthis
?
Ответ №1:
На этом этапе я не могу воспроизвести проблему, но симптом говорит о том, что ваша страница обновляется при нажатии на привязку, потому что вы не предотвращаете действие по умолчанию. Есть toggleFPR
вызов preventDefault
для объекта события, который он получает:
toggleFPR(event) {
// ^^^^^ ------------ ***
event.preventDefault(); // ***
console.log('Setting fprActive from ', this.state.fprActive, ' to ', !this.state.fprActive);
this.setState({
fprActive: !this.state.fprActive
});
}
Отдельно: здесь вы нарушаете одно из фундаментальных правил React:
console.log('Setting fprActive from ', this.state.fprActive, ' to ', !this.state.fprActive);
this.setState({
fprActive: !this.state.fprActive
});
При настройке состояния на основе существующего состояния вы должны использовать версию обратного вызова, а не версию, в которую вы передаете объект:
this.setState(({fprActive}) => {
console.log('Setting fprActive from ', fprActive, ' to ', !fprActive);
return {fprActive: !fprActive};
});
Если вы этого не сделаете, он будет работать большую часть времени и иногда будет давать сбой по труднодиагностируемым причинам.
Комментарии:
1. Это работает отлично! Кое-что, что я заметил, это то, что когда я поменял местами теги <a></a> для тега <div></div> , повторный рендеринг страницы отсутствует (без event.preventDefault()). Кажется, что под капотом вызываются теги <a>
2. @AKJ — Я добавил примечание в конец ответа, ваш
setState
вызов нарушает одно из фундаментальных правил React, поэтому вы захотите это исправить. Приятного кодирования!3. большое вам спасибо за улучшение кода. Могу ли я узнать, откуда
({fprActive})
взялось? А также я внес эти изменения, но я хочу понять это, а не копировать вслепую 🙂4. @AKJ — Это разрушает список параметров. Версия обратного вызова
setState
получает объект текущего состояния в качестве своего аргумента. При использовании{fprActive}
в списке параметров из него извлекается толькоfprActive
свойство. Кстати, я рад, что это сработало, потому что я не смог воспроизвести проблему изолированно … 🙂5. другими словами, если у меня есть другие атрибуты (скажем, attr1 amp; attr2) в ` this.state = {…}` в конструкторе, я мог бы сделать это также:
this.setState(({fprActive, attr1, attr2}) => {...});
?