react组件数组元素属性发生变化时,setState页面不更新

今天遇到的问题是:组件内对数组元素进行修改后数据有变化但是页面没重新渲染
话说这是因为组件没能够识别数组的变化,所以页面没有重新渲染
所以只要让组件感知到你发生了改变,就可以达到刷新的效果

import React, { Component } from 'react';
import './App.css';
import Todo from './components/todo/index'
import { Table, Button } from 'element-react';
class App extends Component {
  constructor(props) {
    super(props);
    this.state =  [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄'
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1519 弄'
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1516 弄'
      },{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄'
      }, {
        date: '2016-05-01',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1519 弄'
      }, {
        date: '2016-05-03',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1516 弄'
      }]
  }
  render() {
    return (
     <div>
       <Todo list={this.state.data}/>
       <Table
           style={{width: '100%'}}
           columns={this.state.columns}
           data={this.state.data}
       />
       <Button type="primary" onClick={this.addData.bind(this)}>添加</Button>
     </div>
    );
  }

  addData () {
    let obj = {
      date: '2018-05-07',
      name: '小明',
      address: ''
    };
    let data = this.state.data;

    data.push(obj);
    this.setState({
      data: data
    });
    console.log(this.state);
  }
}

export default App;

上面代码中 通过setState设置data的值发现视图并没有更新,原因是数组的赋值是引用传递的,data = this.state.data其实是将this.state.data的内存地址复制给了data,所以执行data.push(obj)实际上相当于执行了 this.state.data.push(obj),因为地址指向一个地方,所以react的虚拟dom发现state里面的data没有变化,所以不更新视图,而这时可以使用一个新数组:

 let data = [...this.state.data];

同理,React Hook也会发生上述问题

import React, { useState, useEffect } from "react";
import TestItem from "../TestItem/TestItem.js";
import Count from "../count";

const _ = {
  map: require("lodash/map"),
  fill: require("lodash/fill"),
  set: require("lodash/set")
};

const Main = () => {
  const [name, setName] = useState("");
  const [count, setCount] = useState(0);
  const [datas, setDatas] = useState([]);

  const getDatas = () => {
    setDatas([
      { title: "分类一", index: 0 },
      { title: "分类二", index: 1 },
      { title: "分类三", index: 2 }
    ]);
  };

  useEffect(() => {
    setName("hello world");
    getDatas();
  }, []);

  useEffect(() => {
    console.log("data has changed !!!!!");
  }, [datas]);

  const onClick = index => {
    const result = _.set(datas, [index, "title"], "哎呀我去");

    // ❌错误的方式
    // setDatas(result)

    // 方法一
    // setDatas(JSON.parse(JSON.stringify(result)));

    // 方法二
    // setDatas([...result]);

    // 方法三
    let tmp = [...datas]; // 切不可 let tmp = datas
    tmp[index].title = "哈哈哈哈";
    setDatas(tmp);
    
     // 方法四
     //使用lodash的_.cloneDeep()
     
  };

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <div>
        {datas.map((item, index) => {
          return <TestItem data={item} key={index} onClick={onClick} />;
        })}
      </div>
      <div>
        <Count count={count} handleClick={handleClick} />
      </div>
    </div>
  );
};

export default Main;

涉及到的知识点是对象的深拷贝与浅拷贝,这里有一篇关于深拷贝与浅拷贝的文章很好,感兴趣的童鞋可以看一下哦~~js浅拷贝与深拷贝的区别和实现方式

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值