React setStats数组不更新,百思不得其解。

楼楼今日遇到个坑爹的问题。
就是 this.setStats({}) 对 this.stats 不更新问题
问题是这样的
constructor(props) {

    super(props);
    this.state = {
        imageList: []
    }

    WechatService.getMaterialOrealList("image").then((result) => {
        this.setState({
            imageList: result
        })
    });

}

 async handleInputChangeUpload(event) {
    var target = event.target;
    var file = target.files[0];

    var formData = new FormData();
    formData.append('file', file);

    var result = await WechatService.updateMaterialImage(formData);

    var lists = this.state.imageList;
    lists.push(result);
    console.log(lists);
    //同步更新
    this.setState((prevState, props) => ({
        imageList: lists
    }))

}

图片描述
数组的长度已经变成了11可是 render 并没有更新!!,这是为什么呢?
此方法已经是谷歌出来的东西,可是好像并没有成功
this.setState((prevState, props) => ({

       imageList: lists
   }))

但是楼主看了一下elementsUI 的代码后进行一次修改后,发现一下方案倒是成功了。百思不得其解,不知道那位小兄弟可以解答一下。
constructor(props) {

   super(props);
   this.state = {
   //这是把数组用一个对象包含起来
       data: {
           imageList: []
       }
   }

}

componentWillMount() {

   WechatService.getMaterialOrealList("image").then((result) => {
       this.setState({
           data: Object.assign({}, {
               imageList: result
           })
       })
   });

}

handleUpload() {

   this.refs.inputFile.click();

}

async handleInputChangeUpload(event) {

   var target = event.target;
   var file = target.files[0];

   var formData = new FormData();
   formData.append('file', file);

   var result = await WechatService.updateMaterialImage(formData);

   var lists = this.state.data.imageList;
   lists.push(result);
   this.setState((prevState, props) => ({
   //浅拷贝、对象属性的合并
       data: Object.assign({}, { imageList: lists })
   }))

   setTimeout(() => {
       console.log(this.state.data);
   });

}
这样使用对象进行修改的数组变量反而更新了。
图片描述
这是为什么呢?
无法解答

作者:傻梦兽
链接:https://juejin.im/post/5b1a22...
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

阅读 11k
3 个回答

楼上的回答有一点缺陷。

白天我看到这个问题也是这么想的,可是setStaterender并没有自带的shallow compare,猜想不成立。刚才自己试了一下,即使是空的setState也可以触发当前组件re-render

至于题目中出现的情况,我猜测有fetch的容器组件跟列表项展示组件是分开的,同时展示组件使用了PureComponent或者在ShouldComponentUpdate中做了shallow compare,或者是其他的节流方案。总之对于不改变地址的imageList数组而言,是无法触发展示组件的re-render的。

楼上回答的缺陷在于,如果不使用节流方案,那么React本身不会进行任何shallow compare,所有的变动都是基于最终得出的Vitural DOM diff来进行的,用来对比的不是imageList本身,而是每一个由imageList map出来的item。即若能触发展示组件的re-render,即使不改变数组的引用,依然可以正确显示变动

var lists = this.state.imageList;
lists.push(result);
console.log(lists);
//同步更新
this.setState((prevState, props) => ({
    imageList: lists
}));

有一个点你要弄清楚,在js中,数组的赋值是引用传递的,list.push相当于直接改变了数组对应的内存块,这样修改,react内部用来做对比的imageList也被你改了,因为都是指向同一块内存。最后re-render的时候,react发现你的imageList是一样的,好的,没有变化,不更新了。

你可以这么做:

// 使用新的数组
var lists = [...this.state.imageList];
// 其他语句不变
新手上路,请多包涵

setstate 只做浅比较

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题