【发布时间】:2015-08-12 05:56:23
【问题描述】:
我正在编写一个脚本,该脚本根据下拉菜单的高度和屏幕上输入的位置将下拉菜单移动到输入下方或上方。我还想根据其方向将修饰符设置为下拉菜单。
但是在componentDidUpdate 内部使用setState 会创建一个无限循环(这很明显)
我找到了使用getDOMNode 并直接将类名设置为下拉菜单的解决方案,但我觉得应该有更好的解决方案使用 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>
);
}
});
【问题讨论】:
-
我认为这里的诀窍是
setState将总是触发重新渲染。而不是检查state.top并多次调用setState,只需跟踪您希望state.top在局部变量中的内容,然后在componentDidUpdate结束时调用setState,前提是您的局部变量没有匹配state.top。就目前而言,您在第一次重新渲染后立即重置state.top,这会使您陷入无限循环。 -
在this fiddle 中查看
componentDidUpdate的两种不同实现。 -
该死的!局部变量解决了整个问题,我怎么没被 mysef 弄明白!谢谢!
-
我认为你应该接受下面的答案。如果你再读一遍,我想你会发现它确实充分回答了最初的问题。
-
为什么没有人建议将条件转移到
componentShouldUpdate?
标签: javascript reactjs ecmascript-6