我有一个非常简单的自定义组件:两个带有按钮的 select
列表,用于将 options
从 available (左)列表移动到 selected (右)列表 . 当然,移动的元素不应再显示在它移动的列表中 . 虽然两个按钮都成功地将元素添加到目标,但它不会从源中删除,因为当我将减少的项目数组传递给 setState
时,渲染仍然会返回原始列表 .
EDIT 发布了大部分组件代码以供澄清 . 问题方法是 addItems
和 removeItems
,其中 setState
被调用 . 在这两种情况下,减少/过滤的数组属性都是不更新的;添加的一个总是正确更新 .
... imports
interface JoinedListState {
availableItems: ListItem[]
selectedItems: ListItem[]
}
export class JoinedList extends React.Component<JoinedListState, any>{
// Create new arrays of the proper available and selected then set the new
// state
private addItems(newItems: ListItem[]) {
let oldSelected = this.props.selectedItems;
oldSelected.push.apply(oldSelected, newItems);
let newSelected = oldSelected.sort((a, b) => {
let nameA = a.value.toUpperCase();
let nameB = b.value.toUpperCase();
if (nameA < nameB) {
return -1
}
return 1
});
let newAvailable = this.props.availableItems
.slice(0) // updated on recommendation of Sasha Kos
.filter((item) => {
return newItems.findIndex(i => i.id == item.id) == -1
});
this.setState({
availableItems: newAvailable,
selectedItems: newSelected
});
}
// Create new arrays of the proper available and selected then set the
//new state
private removeItems(removedItems: ListItem[]) {
.. same approach as addItems
let newSelected = this.props.selectedItems.filter((item) => {
// return only the items whose id does not exist on the newly
//removed items list
return removedItems.findIndex(i => i.id == item.id) == -1
})
this.setState({
availableItems: newAvailable,
selectedItems: newSelected
})
}
// Get the selected items by querying the DOM and send them to function
// to update state
addSelected(event: React.FormEvent<HTMLButtonElement>) {
// Code removed for brevity: uses the event object to find the
//selected objects and builds a ListItem array called 'selected'
//to pass to addItems
this.addItems(selected)
}
removeSelected(event: React.FormEvent<HTMLButtonElement>) {
// Code removed for brevity: uses the event object to find the
//selected objects and builds a ListItem array called 'selected'
//to pass to addItems
this.removeItems(selected)
}
render() {
let aItems = this.renderOptionList(this.props.availableItems),
sItems = this.renderOptionList(this.props.selectedItems);
return (
<div className='joined-list-container'>
<select key='available_list' className='available-list form-
control' multiple>
{aItems}
</select>
<span className='button-container'>
<button key='button1' className='btn btn-success'
onClick={this.addSelected.bind(this)}>
<span className='glyphicon glyphicon-chevron-right'>
</span>
</button>
<button key='button2' className='btn btn-danger'
onClick={this.removeSelected.bind(this)}>
<span className='glyphicon glyphicon-chevron-left'>
</span>
</button>
</span>
<select key='selected_list' className='selected-list form-
control' multiple>
{sItems}
</select>
</div>
)
}
renderOptionList(items: ListItem[]) {
return items.map((item, idx) => {
let key = `${item.value}_${idx}`
return (
<option value={item.id} key={key}>{item.value}</option>
)
})
}
}
(对不起任何有缺陷的格式,发帖很棘手)
当这启动新渲染时,selectedItems列表会使用新项正确更新,但availableItems始终是原始数组(是的,我已确保 newAvailable
数组已正确过滤掉),即使我尝试
this.setState({
availableItems: [],
selectedItems: newSelected
})
我在下一个渲染中获得了原始的availableItems数组 .
通过 setState
返回类似但更短的数组是否存在一些细微差别?我可以't find anything referencing this behavior, and not sure what I'失踪 .
谢谢
2 回答
这是问题:
您在此处更新this.props.selectedItems,但是对于availableItems:
在这里,您不直接更新this.props.availableItems . 这很重要的原因是当你调用setState并且触发render时这些方法:
使用this.props返回数组,而不是this.state . this.props.selectedItems已更改,因此返回不同的数组,而this.props.availableItems未更改 .
tl; dr - 在将数组传递给renderOptionList方法时使用this.state而不是this.props .
根据mozilla docs Array.prototype.filter应该创建新的数组,但是描述的症状表明你只得到2个引用一个数组,所以没有重新渲染 . 所以请试试这个