我有这个组件:
// imports
export default class TabViewExample extends Component {
state = {
index: 0,
routes: [
{ key: 'first', title: 'Drop-Off', selected: true },
{ key: 'second', title: 'Pick up', selected: false },
],
};
handleIndexChange = index => this.setState({ index });
handleStateIndexChange = () => { // FUNCTION WITH THE ERROR
const { index } = this.state;
this.setState(({ routes }) => ({
routes: routes.map((route, idx) => ({
...route,
selected: idx === index,
})),
}));
};
renderTabBar = props => {
const { routes } = this.state;
this.handleStateIndexChange(); // HERE I GET THE ERROR
return (
<View style={tabViewStyles.tabBar}>
{props.navigationState.routes.map((route, i) => {
return (
<>
<TouchableOpacity
key={route.key}
style={[
tabViewStyles[`tabStyle_${i}`],
]}
onPress={() => this.setState({ index: i })}
>
<Text>
{route.title}
</Text>
// THE FUNCTION ATTEMPTS TO SHOW AN ELEMENT WHEN
// THE INDEX OF A ROUTE IS selected true
{routes[i].selected && (
<View
style={{
flex: 1,
}}
>
<View
style={{
transform: [{ rotateZ: '45deg' }],
}}
/>
</View>
)}
</TouchableOpacity>
</>
);
})}
</View>
);
};
renderScene = SceneMap({
first: this.props.FirstRoute,
second: this.props.SecondRoute,
});
render() {
return (
<TabView
navigationState={this.state}
renderScene={this.renderScene}
renderTabBar={this.renderTabBar}
onIndexChange={this.handleIndexChange}
/>
);
}
}
完整错误:
不变违反:不变违反:超过最大更新深度。当组件重复调用componentWillUpdate或componentDidUpdate内部的setState时,可能会发生这种情况。 React限制了嵌套更新的数量,以防止无限循环。
这是给出错误的函数:
handleStateIndexChange = () => { // FUNCTION WITH THE ERROR
const { index } = this.state;
this.setState(({ routes }) => ({
routes: routes.map((route, idx) => ({
...route,
selected: idx === index,
})),
}));
};
我需要做的就是将selected
的状态设置为true
,以便可以切换组件的可见性。
答案 0 :(得分:1)
如上面的注释所述,您不能直接在渲染函数内部调用setState
。
我看不出有任何理由将selected
值保持在您的状态,因为它仅取决于其中的另一个值,该信息是多余的。
您应该从selected
中的所有对象中删除routes
并更改JSX条件:
{routes[i].selected &&
到以下内容:
{i === this.state.index &&
要产生相同的结果。
您现在可以从代码中删除handleStateIndexChange
答案 1 :(得分:0)
由于React将以批处理状态更新的方式,如果您需要基于先前状态设置状态,则应在回调中进行所有解构操作:
handleStateIndexChange = () => {
this.setState(({ index, routes }) => ({
routes: routes.map((route, idx) => ({
...route,
selected: idx === index,
})),
}));
};
此外,正如@Adeel提到的那样,您不应从this.setState
执行上下文内部调用render
。改为移动该呼叫componentDidUpdate
。
答案 2 :(得分:0)
在setState
中调用render
是无限重新渲染loop
的实际原因,
因为设置state
会调用重新渲染,而调用另一个setState
则会调用另一个重新渲染,等等。
因此,我建议将setState
部分移至componentDidUpdate
并在那里进行控制。这是我的意思approximation,描述内容不多。
class App extends React.Component {
state = {
index: 0,
routes: [
{
key: "first",
title: "Drop-Off",
selected: true
},
{
key: "second",
title: "Pick up",
selected: false
}
]
};
componentDidUpdate(_, prevState) {
if (prevState.index !== this.state.index) {
this.handleStateIndexChange();
}
}
handleIndexChange = () => {
const randomIndexBetweenZeroAndOne = (Math.random() * 100) % 2 | 0;
this.setState({
index: randomIndexBetweenZeroAndOne
});
};
getMappedRoutes = (routes, index) =>
routes.map((route, idx) => ({
...route,
selected: idx === index
}));
handleStateIndexChange = () => {
this.setState(({ routes, index }) => ({
routes: this.getMappedRoutes(routes, index)
}));
};
render() {
const { routes } = this.state;
return (
<>
<button onClick={this.handleIndexChange}>Change Index</button>
{this.state.routes.map(JSON.stringify)}
</>
);
}
}