我有一个子组件(调用另一个组件),我从其父组件中调用一个函数:
这是子组件中的render方法:
render() {
...
return (
<secondChild
getName={(name) => {
this.props.(handleName(name))
}
}
/>
);
在父组件中,我将使用setState:
handleName = (name) => {
…
this.setState(….);
}
父级中的setState导致重新渲染,因此将重新渲染子级。这导致无限循环并最终导致“超出最大堆栈...&#34;
我想知道为什么孩子会在重新渲染后立即调用该函数?我应该更改getName
吗? [因为它是一个箭头功能]
如何更改代码以避免此循环?
答案 0 :(得分:2)
出现此问题可能是因为您在渲染子组件期间尝试更改父组件的state
。这将导致无限循环,因为状态更改会导致组件重新渲染,这意味着父级将重新渲染其子级,从而导致它们调用更新父级state
的相同方法。
您通常会更改状态以响应某些用户操作,或者从api中获取某些数据后,但在呈现组件时不会。如果您需要从api获取数据并将其设置为您使用componentDidMount
的状态,请参阅react docs。像这样:
componentDidMount() {
// safe to call setState here
this.setState({ name : 'value' });
}
答案 1 :(得分:1)
您实际上是在生成一个无限循环。虽然我们没有子组件的代码,但如果每次渲染时至少调用一次getName,这将导致问题。
解决问题的一种方法是让子组件无法重新渲染。通过给予它;
shouldComponentUpdate() {
return false;
}
你可以确保它只被渲染一次。请注意,此函数是可扩展的,并且取决于nextProps和nextState,您可以使它在props更新时不会重新呈现但是当状态执行时,或者跳过重新呈现以进行某些更改而不是其他更改。
例如,以下代码仅在组件的状态更新时才会重新呈现;
shouldComponentUpdate(nextProps, nextState) {
let stateHasChanged = false;
Object.keys(nextState).forEach((stateKey) => {
if (this.state[stateKey] !== nextState[stateKey]) {
stateHasChanged = true;
}
});
return stateHasChanged;
}
正如评论中所指出的,快速免责声明是您应该尝试尊重React的生命周期而不是在渲染中使用setState。但是,如果您希望这样做,那就是这样。
答案 2 :(得分:1)
在父母中尝试isChildMounted
状态,如下所示:
:
handleName = (name) => {
if(!this.state.isChildMounted){
this.setState({
isChildMounted: true,
...
...
});
}
}