我有一个非常简单的自定义组件:两个select列表,用来将options从available (左)列表移动到selected (右)列表。自然,被移动的元素不应该再出现在它被移出的列表中。尽管这两个按钮都成功地将元素添加到目标,但它并没有从源中删除,因为当我将缩减后的项目数组传递给setState时,呈现仍然返回原始列表。
编辑发布了大部分组件代码,以求澄清。有问题的方法是调用setState的addItems和removeItems。在这两种情况下,无论哪个数组属性被减少/过滤,都是没有更新的属性;添加到的属性总是正确更新。
... 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将类似但更短的数组返回给state是否有一些细微差别?我找不到任何引用此行为的内容,也不确定我遗漏了什么。
谢谢
发布于 2018-06-08 04:33:59
这是问题所在:
let oldSelected = this.props.selectedItems;
oldSelected.push.apply(oldSelected, newItems);您在这里更新的是this.props.selectedItems,但对于availableItems:
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.props.availableItems。这很重要的原因是,当您调用setState并触发render时,会触发这些方法:
let aItems = this.renderOptionList(this.props.availableItems),
sItems = this.renderOptionList(this.props.selectedItems);使用this.props返回数组,而不是this.state。this.props.selectedItems已更改,因此返回不同的数组,而this.props.availableItems未更改。
tl;dr -在将数组传递给renderOptionList方法时,使用this.state而不是this.props。
发布于 2018-06-08 03:44:00
根据mozilla docs的说法,Array.prototype.filter应该创建新的数组,但描述的症状表明你只有2个对一个数组的引用,所以没有重新渲染。所以请试试这个
let newAvailable = this.props.availableItems
.slice(0) /* clones your array */
.filter((item) => {
return newItems.findIndex(i => i.id == item.id) == -1
});
this.setState({
availableItems: newAvailable,
selectedItems: newSelected
});
https://stackoverflow.com/questions/50748913
复制相似问题