native: ListView, how to push new rows from top

I have been trying to understand how I could manage to make a ListView that can recieve often new data and push it to the front. With the code below, the list does not reflect change correctly, instead of having a new row at the top, the last one is beeing duplicated..

'use strict';

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  ListView,
  TouchableHighlight,
} = React;

var listview = React.createClass({
  rows: [],

  _rowHasChanged: function (r1, r2) {
    // if (r1 !== r2)
    //   console.log('rowChanged', r1, r2);
    // else
    //   console.log('row didn't Changed', r1, r2);
    return r1 !== r2;
  },

  getInitialState: function() {
    return {
      dataSource: new ListView.DataSource({rowHasChanged: this._rowHasChanged}),
    };
  },

  componentDidMount: function () {
    this.rows = [
      {id: 0, text: '0: text'},
      {id: 1, text: '1: text'},
      {id: 2, text: '2: text'},
      {id: 3, text: '3: text'},
    ];

    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(this.rows),
    });
  },

  pushTopRow: function () {
    var id = this.rows.length;
    this.rows.unshift({id: id, text: id + ': text'});

    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(this.rows),
    });
  },

  render: function() {
    return (
      <View style={styles.container}>
        <ListView
          dataSource={this.state.dataSource}
          renderRow={(rowData) => <Text key={rowData.id}>{rowData.text}</Text>}
        />
        <TouchableHighlight
          onPress={this.pushTopRow}>
          <Text>PUSH TOP</Text>
        </TouchableHighlight>
      </View>
    );
  },
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'orange',
  },
});

AppRegistry.registerComponent('listview', () => listview);

then I tried:

pushTopRow: function () {
    var id = this.rows.length;
    var newRow = [{id: id, text: id + ': text'}];
    this.rows = newRow.concat(this.rows);

    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(this.rows),
    });
  },

this actually works, but I don't understand why first method doesn't work. I'm trying to figure out what is the best practises for handling with ListView:

  • Am I supposed to use cloneWithRows with a new array in any case, even for a single add/delete operation ?
  • Is there anything else to setup for the ListView/DataSource mechanics to works correctly with minimum redraw (keys, hasRowChanged specific comparision ?),
  • kind of lacking of documentations and exemples, it would be great to clarify it for me and anyone. thanks you & have a good code day.


    ListView assigns component keys by data source index, and consequently will rerender all rows whenever the datasource is prepended to. If your row data has any unique id, you can create a modified ListView that uses that as the key. See for example PrependableListView which will use the id attribute on your row data.

    Note: this component is not generalized and will fail if there is no id property defined.

    Note: I realize this does not answer your whole question, just a specific peculularity about prepending to the datasource.

    链接地址: http://www.djcxy.com/p/28024.html

    上一篇: 如何进行单元测试以测试检查请求标头的方法?

    下一篇: native:ListView,如何从顶部推新的行