![](/img/trans.png)
[英]Why isn't child component re-rendered even though parent state is updated using hooks
[英]Even after passing updated value from parent to child, child is not rendered
在父组件中,我从服务器接收数据,然后将此数据映射为jsx格式。 在此映射内部,我有一个子组件,并尝试将值从父状态传递给子状态作为属性,但是,当我更新此值的状态时,不会执行子项的渲染功能。
预期的行为:作为用户,我看到一个项目列表。 如果我单击某个项目,则它应变为选中状态。
export class ReactSample extends React.Component {
constructor(props){
super(props);
this.state = {
items: [],
mappedItems: [],
selectedIds: [],
isSelected: false,
clickedTripId: null
};
this.toggleSelection = this.toggleSelection.bind(this);
}
componentWillMount(){
console.log("Component mounting")
}
toggleSelection (id, e) {
if(!_.includes(this.state.selectedIds, id)) {
this.setState((state) => ({selectedIds:
state.selectedIds.concat(id)}));
this.setState(() => ({clickedTripId: id}));
this.mapItems(this.state.items);
}
}
componentDidMount() {
const self = this;
MyService.getItems()
.then(res => {
self.setState(() => ({ items: res.allItems }));
self.setState(() => ({ mappedItems:
this.mapItems(res.allItems) }));
}
)
}
mapItems (items) {
return items.map(trip => {
return (
<li key={trip.id} onClick={(e) => (this.toggleSelection(trip.id,
e))}>
<span>{trip.title}</span>
<Tick ticked={this.state.clickedTripId}/>
<span className="close-item"></span>
</li>
);
});
}
getItems() {
}
render() {
return (
<div>
<a className="title">This is a react component!</a>
<Spinner showSpinner={this.state.items.length <= 0}/>
<div className="items-container">
<ul id="itemsList">
{this.state.mappedItems}
</ul>
</div>
</div>
);
}
}
export class Tick extends React.Component {
constructor(props) {
super(props);
}
render() {
console.log('RENDER');
return (<span className={this.props.ticked ? 'tick display' :
'tick hide' }></span>);
}
}
我看到几个问题。
在toggleSelection
您不会对mapItems的结果做任何事情。 如果您mappedItems
状态中删除mappedItems
,而只是在render方法中调用mapItems
,则可以避免这种错误。
另一个问题是您正在传递this.state.clickedTripId
作为已ticked
属性。 我假设您打算传递类似this.state.clickedTripId === trip.id
。
莱恩已经说了,问题是, mappedItems
在哪里都不更新toggleSelection
被点击。 从代码中可以明显mapItems
,mapItems以jsx格式返回数据。 要对其进行更新,我必须调用this.setState({mappedItems: this.mapItems(this.state.items)})
,这意味着我调用了mapItems
,然后将结果分配给该状态。 在这种情况下,我的列表将被更新, Tick
组件将收到this.state.clickedItemId
作为tick
属性。 要使此代码正常工作,还需要解决另一个问题:在this.state.clickedItemId
更新后,需要更新此映射列表。 setState
方法是异步的,这意味着仅在this.state.clickedItemId
更新之后this.state.clickedItemId
必须调用this.setState({mappedItems: this.mapItems(this.state.items)})
。 为此, setState
方法可以接收回调函数作为第二个参数。 代码段如下:
toggleSelection (id, e) {
if(!_.includes(this.state.selectedIds, id)) {
this.setState((state) => ({
clickedItemId: id,
selectedIds: state.selectedIds.concat(id)
}), () => this.setState({mappedItems: this.mapItems(this.state.items)}));
}
}
在这种情况下,在执行mapItems
函数时,来自此处所需状态的所有数据都将已更新:
mapItems (items) {
return items.map(item => {
return (
<li key={item.id} onClick={(e) => (this.toggleSelection(item.id, e))}>
<span>{item.title}</span>
<span>{this.state.clickedItemId}</span>
<Tick ticked={this.state.clickedItemId === item.id}/>
<span className="close-item"></span>
</li>
);
});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.