ListView做了个todolist,信息保存在数组中,发现删除列表中任意一条信息,都是最后一个消失……



  • 不管删除哪一条,总是最后一条消失……求解原因……
    下面上些主要代码,constructor里,this.arr用来保存信息的,dataSource就是列表信息,word是输入的内容。

    constructor(props) {
    super(props)
    let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    this.arr = []
    this.state = {
    dataSource: ds.cloneWithRows(this.arr),
    word: ' '
    }
    };

    这个是用来展示数据的列表
    <ListView bounces={false} style={styles.listview} dataSource={this.state.dataSource}
    renderRow={(data, sectionID, rowID)=>this.rowData(data, sectionID, rowID)} />

    这是列表中每一行的元素
    rowData(data, sectionID, rowID) {
    return (
    <TouchableOpacity style={styles.list}>
    <Text>{data}</Text>
    <TouchableHighlight style={styles.closePosition} underlayColor="#f00" onPress={(rid)=>this.removeList(rowID)}>
    <Image style={styles.closeImg} source={require("./iconfont-icon32.png")}/>
    </TouchableHighlight>
    </TouchableOpacity>
    )
    };

    这是执行删除的代码
    removeList(rowID) {
    this.arr.splice(rowID, 1)
    this.setState({
    dataSource: this.state.dataSource.cloneWithRows(this.arr)
    })
    };

    很纳闷,中间也输出过this.arr,发现的确是我点击的那条被删了,但是调用到this.state以后,呈现出来的数据就是最后一条不见了,不是很懂,发帖求解原因……


  • administrators

    问题正出在常常有人问的这个

    let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    

    当dataSource更新时,ListView怎么知道哪些行更新了呢?那它就看rowHasChanged。官方给我们的例子是r1 !== r2,直接比较,是个大坑。用于基本类型是可以的,然则基本类型以外就行不通(object、array都不行)。哪怕object、array的内容完全一样,直接比较返回的结果也是false,因为它们是引用类型,比较的是引用的地址(指针)。
    回到你这个例子中,你删除了数组中的一项,其实是把这一项之后的所有指针都往前挪了一个,在rowHasChanged看来,所有项的比较结果都是true,只是最后一个不见了。

    所以,你需要自己实现一个rowHasChanged,如果row没有特征id,那你就得深比较(比如JSON.stringify之后再进行字符串的比较)。



  • 原ListView的数据是arr,你移除arr中数据使用splice,所以新ListView的数据还是之前的arr。cloneWithRows会把新旧数据进行比较,知道哪些是需要更新的。由于你cloneWithRows方法只传了一个参数,则会按照数组的顺序进行两两比较。所以rowHasChanged中比较的一直是同样的两个元素,无论rowHasChanged怎么写,还是没有解决问题。

    为什么最后一条不见了呢,应该是数目减1了,导致ListView认为最后一条不存在,则移除了。

    你试试,this.arr.concat().splice(rowID, 1)。//创建新数组,再进行移除元素。不建议直接更改原数组
    ps:这只是我的个人理解,没有试验过,不一定正确。



  • @zdk 说:

    this.arr.concat().splice(rowID, 1)

    this.arr=this.arr.concat().splice(rowID, 1);



  • @zdk 试了下,思路ok的。不过你那样好像取到了相反的那部分数组,我这边写法稍微变一变
    this.arr = this.arr.concat();
    this.arr.splice(rowID, 1);
    这样就可以了,很感谢大半夜回复~~


登录后回复