6

I have a React Native ListView that seems to be removing the wrong row in the UI when I update the state with the new sections & rows - The row I deleted stays, but the one, or sometimes even, 2 below that gets removed until I reload the app.

What am I doing wrong?

constructor(props) {
  super(props)

  this.state = {
    dataState: DataState.STATE_NOT_LOADED,
    dataSource: new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1.identifier !== r2.identifier,
      sectionHeaderHasChanged: (s1, s2) => s1 !== s2
    })
  };
}

componentDidMount() {
  this.loadData();
}

loadData() {
  this.setState({
    dataState: DataState.STATE_LOADING
  });

  User.getDocs()
    .bind(this)
    .then(results => {
      var docs = _.groupBy(results, function (d) {
        return d.createdAt.format('MMMM D');
      });

      this.setState({
        dataState: DataState.STATE_LOADED,
        dataSource: this.state.dataSource.cloneWithRowsAndSections(docs)
      });
    })
    .catch(error => {
      console.log(error);

      this.setState({
        dataState: DataState.STATE_ERROR
      });
    });
}

onTrackPressed(doc) {
  User.untrackDoc(doc)
    .bind(this)
    .tap(() => {
      this.loadData();
    });
}

renderRow(result) {
  return (
    <DocRow
      style={styles.row}
      doc={result}
      tracked={true}
      onPress={() => this.onRowPressed(result)}
      onTrackPress={() => this.onTrackPressed(result)}/>
  );
}
Hannes Johansson
  • 1,794
  • 2
  • 15
  • 28
nullfox
  • 597
  • 1
  • 4
  • 16

1 Answers1

4

I'm not sure if this is the proper answer, but it's worked for me until I can find a better explanation/better answer.

I recently had this same question, as did someone else I was talking to. They fixed it by adding a key property to the ListView. Apparently, you need to add key to ListView because the table rows are super dynamic, and it seems like not having the key on each row was causing ListView to incorrectly choose what row to get deleted.

<ListView
  key={putSomethingUniqueInHere}
  dataSource={this.state.dataSource}
  renderRow={this.renderRow.bind(this)}
/>
KirRogue
  • 231
  • 1
  • 2
  • 9
  • 1
    Because `ListView` uses [dynamic children](http://facebook.github.io/react/docs/multiple-components.html#dynamic-children) the `key` prop must be placed - in this case - on the outermost component returned by the bound `renderRow` callback. Same thing goes for any separators created using `renderSeparator`. – vhs Oct 06 '15 at 17:54
  • Thanks I had the same issue, adding the key resolved my issue :) – Jerome Mouneyrac Feb 15 '16 at 09:29