我对React还是很陌生,我正在把头发拉出来:
HTML
<div id="root"></div>
JS
class Child extends React.Component {
constructor(props) {
super(props);
this.state = { title: props.title };
}
render() {
return ()<div>{this.state.title}</div>);
}
}
class TestApp extends React.Component {
constructor(props) {
super(props);
this.state = {
children: [
<Child title='a' />,
<Child title='b' />
]};
}
componentDidUpdate(prevProps, prevState) {
console.log('[componentDidUpdate]');
console.log('prevChildren: ' + prevState.children.map(c => c.props.title).join(', '));
console.log('children: ' + this.state.children.map(c => c.props.title).join(', '));
}
handleOnClick = () => {
console.log('[handleOnClick]');
this.setState((prevState) => {
return {
children: [
<Child title='c' />,
<Child title='d' />
]
};
});
};
render() {
console.log('[render]');
return (
<div>
<div>TEST</div>
{this.state.children}
<button onClick={this.handleOnClick}>CHANGE</button>
</div>
)
}
}
ReactDOM.render(<TestApp />, document.getElementById('root'));
CodePen:https://codepen.io/robloche/pen/xmGMBy
当我单击按钮时,控制台中发生的事情是:
[handleOnClick]
[render]
[componentDidUpdate]
prevChildren: a, b
children: c, d
对我来说看起来不错,但是仍然以某种方式显示a
和b
而不是c
和d
...
我想念什么?
答案 0 :(得分:3)
您不应在子组件中使用状态。您对子道具没有任何依赖性,只需使用父组件的道具就可以了。
更改:
return (<div>{this.state.title}</div>);
到
return (<div>{this.props.title}</div>);
您现在面临的问题是父代已更改为c,d,并且也已作为子代传递,但是由于react没有任何键更新或状态更新,因此它不会重新呈现该组件。最好的方法是使用从父级传递来的道具并使用它们。
答案 1 :(得分:3)
由于您有一个Child
元素数组,因此React无法区分它们何时实际被更新/替换为新元素。
为每个key
添加唯一的Child
,例如,
<Child key='a' title='a'/>
,
<Child key='b' title='b'/>
,
等
NB!当处理组件数组时,key
属性是强制性的,虽然在这种情况下也有帮助,但是您当前的方法不是很理想。
您应该只存储它们的值(在这种情况下为title
,然后使用render()
方法来处理状态,而不是在状态更改时创建全新的Components。
以下是伪伪代码,因为我只添加了相关部分以显示其工作原理。
constructor() {
this.state = {
children: ['a', 'b']
}
}
onClick() {
this.setState({
children: ['c', 'd']
});
}
render() {
return (
<>
{this.state.children.map(title => <Child key={title} title={title}/>)}
</>
);
}