setState () внутри componentDidUpdate()
Я пишу скрипт, который перемещает выпадающий список ниже или выше ввода в зависимости от высоты выпадающего списка и положения ввода на экране. Также я хочу установить модификатор в выпадающее меню в соответствии с его направлением.
Но с помощью setState внутри componentDidUpdate создает бесконечный цикл(что очевидно)
Я нашел решение в использовании getDOMNode и установка classname в выпадающее меню напрямую, но я чувствую, что должно быть лучшее решение с использованием инструментов React. Кто-нибудь может помочь я?
вот часть рабочего кода с getDOMNode (i
немного пренебрегли логикой позиционирования для упрощения кода)
let SearchDropdown = React.createClass({
componentDidUpdate(params) {
let el = this.getDOMNode();
el.classList.remove('dropDown-top');
if(needToMoveOnTop(el)) {
el.top = newTopValue;
el.right = newRightValue;
el.classList.add('dropDown-top');
}
},
render() {
let dataFeed = this.props.dataFeed;
return (
<DropDown >
{dataFeed.map((data, i) => {
return (<DropDownRow key={response.symbol} data={data}/>);
})}
</DropDown>
);
}
});
а вот код с setstate (который создает бесконечный цикл)
let SearchDropdown = React.createClass({
getInitialState() {
return {
top: false
};
},
componentDidUpdate(params) {
let el = this.getDOMNode();
if (this.state.top) {
this.setState({top: false});
}
if(needToMoveOnTop(el)) {
el.top = newTopValue;
el.right = newRightValue;
if (!this.state.top) {
this.setState({top: true});
}
}
},
render() {
let dataFeed = this.props.dataFeed;
let class = cx({'dropDown-top' : this.state.top});
return (
<DropDown className={class} >
{dataFeed.map((data, i) => {
return (<DropDownRow key={response.symbol} data={data}/>);
})}
</DropDown>
);
}
});
5 ответов:
можно использовать
setStateвнутриcomponentDidUpdate. Проблема в том, что каким-то образом вы создаете бесконечный цикл, потому что нет условия останова.основываясь на том, что вам нужны значения, которые предоставляются браузером после визуализации компонента, я думаю, что ваш подход к использованию
componentDidUpdateправильно, он просто нуждается в лучшей обработке условия, которое запускаетsetState.
если вы используете
setStateвнутриcomponentDidUpdateон обновляет компонент, что приводит к вызовуcomponentDidUpdate, который впоследствии называетsetStateснова приводит к бесконечному циклу. Вы должны условно позвонитьsetStateи убедитесь, что условие, нарушающее вызов, происходит в конечном итоге, например:componentDidUpdate: function() { if (condition) { this.setState({..}) } else { //do something else } }если вы только обновляете компонент, отправляя ему реквизиты (он не обновляется setState, за исключением случая внутри componentDidUpdate), вы можете вызвать
setStateвнутриcomponentWillReceivePropsвместоcomponentDidUpdate.
The
componentDidUpdateподписьvoid::componentDidUpdate(previousProps, previousState). С помощью этого вы сможете проверить, какие реквизиты / состояние грязные и позвонитьsetStateсоответственно.пример:
componentDidUpdate(previousProps, previousState) { if (previousProps.data !== this.props.data) { this.setState({/*....*/}) } }
Я бы сказал, что вы должны проверить, если государство уже имеет то же значение, которое вы пытаетесь установить. Если это то же самое, нет смысла снова устанавливать состояние для того же значения.
убедитесь, что вы установили свое состояние следующим образом:
let top = newValue /*true or false*/ if(top !== this.state.top){ this.setState({top}); }
У меня была аналогичная проблема, когда я должен центрировать подсказку. React setState в componentDidUpdate поставил меня в бесконечный цикл, я попробовал условие он работал. Но я обнаружил, что использование в обратном вызове ref дало мне более простое и чистое решение, если вы используете встроенную функцию для обратного вызова ref, вы столкнетесь с нулевой проблемой для каждого обновления компонента. Поэтому используйте ссылку на функцию в обратном вызове ref и установите там состояние, которое инициирует повторную визуализацию