Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sorting ListView's Datasource Does Not Rerender ListView #555

Closed
cadebward opened this issue Apr 1, 2015 · 11 comments
Closed

Sorting ListView's Datasource Does Not Rerender ListView #555

cadebward opened this issue Apr 1, 2015 · 11 comments
Labels
Resolution: Locked This issue was locked by the bot.

Comments

@cadebward
Copy link

As far as I can tell, when I sort the dataSource and then call dataSource.cloneWithRows, it thinks nothing has changed, and thus does not rerender the ListView.

Some background:

I fetch some data, which returns: [{price: 10}, {price: 9}...]. After which i set the state with the new data: this.setState({dataSource: this.state.dataSource.cloneWithRows(data)}). Lets pretend this data is completely sorted. If i reverse the data and set the state, it will not rerender: this.setState({dataSource: this.state.dataSource.cloneWithRows(data.reverse())})

BUT: After messing around a bit, i made a change to the dataSource, like so:

// getInitialState...
dataSource: new ListView.DataSource({
  rowHasChanged: (row1, row2) => true,
}),

...which I know is hackery... But now I can toggle reverse back and forth and it works!

Am I missing something here? Or is this perhaps a side effect of the ListView's optimizations?

@ide
Copy link
Contributor

ide commented Apr 1, 2015

Have you tried using row IDs and passing them into dataSource.cloneWithRows as the second argument?

@williamwa
Copy link

I run into same problem like this. what I do is to dynamicly add item into the data. and then the render is not working correctly. and I fixed it the same way as you did:

dataSource: new ListView.DataSource({
  rowHasChanged: (row1, row2) => true,
}),

@veddermatic
Copy link

I am also having issues with rowHasChanged. If I do this:

var data = [{id: 1, count: 1}, {id: 2, count: 1}];

// in component...
getInitialState: function () {
    var ds = new ListView.DataSource({
        rowHasChanged: function (row1, row2) { 
           console.log(row1.count, row2.count);
           return row1.count !== row2.count;
        }
    });
    return {
        dataSource: ds.cloneWithRows(data)
    }
},
...

And then later:

data[0].count += 1;
this.setState({
        dataSource: this.dataSource.cloneWithRows(data);
});

I get 2 logged for both row1.count and row2.count and my view is never updated. Could be that I am mis-understanding how the data source works, but I think this should work?

@vjeux
Copy link
Contributor

vjeux commented Apr 2, 2015

@veddermatic you need to clone data[0], otherwise this is the same reference so ListViewDataSource can't tell the difference. Look for the many talks about immutability and react to have a better understanding of what is happening

@veddermatic
Copy link

@vjeux Understood, but shouldn't the method cloneWithRows clone for me? I guess it's more of a "misleading method name" issue than a bug. I (incorrectly) assumed that that was happening under the hood in DataSource. Thanks for the clarification though. That's the kick in the pants to start using immutable.js in my little toy project =)

@jamesfzhang
Copy link
Contributor

I'm passing in an identity array, which contains object IDs, as the second argument of cloneWithRows, to sort the ListView. This works just fine in the simulator but on a device, the ordering is not respected.

@willmcclellan
Copy link

Can anyone provide a simple example of how to maintain a sort order with cloneWithRows. I'm sorting our data with javascript but the order is not maintained on re-render. If I understand correctly, the rowIds should be passed as a second argument.. Are these what reference the sort order?

@jamesfzhang
Copy link
Contributor

@willmcclellan Here's a quick example:

let data = [
   {
    "id": "id:1",
    "name": "John",
    "age": 20
  },
  {
    "id": "id:2",
    "name": "Charles",
    "age": 24
  }
]

let identities = data.map(function(d) { return d.id; });
dataSource = dataSource.cloneWithRows(data, identities);

Hope this helps

@willmcclellan
Copy link

@jamesfzhang thanks!

Chris-Petty added a commit to msupply-foundation/mobile that referenced this issue Apr 13, 2016
Also some crude work on sorting by tapping column header (just on name
for now). Something to do with this I suspect:
facebook/react-native#555
@masterkrang
Copy link

masterkrang commented May 5, 2016

What if none of the data has changed but you want to trigger a re-render because there is conditional logic deciding which data shows in each ListView row in your renderRow method? Something to simply re-render the ListView + renderRow seems useful here.

@vjeux
Copy link
Contributor

vjeux commented May 5, 2016

"there is conditional logic deciding which data shows in each ListView row in your renderRow method"

This logic must be using some data in order to decide what to render, the idea is to put this data inside of the datasource or at least in your shouldRowUpdate function.

@facebook facebook locked as resolved and limited conversation to collaborators May 31, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 23, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests

10 participants