首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >React setState不更新精简数组

React setState不更新精简数组
EN

Stack Overflow用户
提问于 2018-06-08 03:31:29
回答 2查看 1.3K关注 0票数 2

我有一个非常简单的自定义组件:两个select列表,用来将optionsavailable (左)列表移动到selected (右)列表。自然,被移动的元素不应该再出现在它被移出的列表中。尽管这两个按钮都成功地将元素添加到目标,但它并没有从源中删除,因为当我将缩减后的项目数组传递给setState时,呈现仍然返回原始列表。

编辑发布了大部分组件代码,以求澄清。有问题的方法是调用setStateaddItemsremoveItems。在这两种情况下,无论哪个数组属性被减少/过滤,都是没有更新的属性;添加到的属性总是正确更新。

代码语言:javascript
复制
    ... 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数组被正确过滤),即使我尝试也是如此

代码语言:javascript
复制
    this.setState({
        availableItems: [],
        selectedItems: newSelected
    })

我在下一次渲染时获得了原始的availableItems数组。

通过setState将类似但更短的数组返回给state是否有一些细微差别?我找不到任何引用此行为的内容,也不确定我遗漏了什么。

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-06-08 04:33:59

这是问题所在:

代码语言:javascript
复制
let oldSelected =  this.props.selectedItems;
        oldSelected.push.apply(oldSelected, newItems);

您在这里更新的是this.props.selectedItems,但对于availableItems:

代码语言:javascript
复制
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时,会触发这些方法:

代码语言:javascript
复制
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。

票数 2
EN

Stack Overflow用户

发布于 2018-06-08 03:44:00

根据mozilla docs的说法,Array.prototype.filter应该创建新的数组,但描述的症状表明你只有2个对一个数组的引用,所以没有重新渲染。所以请试试这个

代码语言:javascript
复制
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
});

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50748913

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档