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

ListView does not re-render a row when property of an object in datasource array is changed #4104

Closed
skleest opened this issue Nov 12, 2015 · 11 comments
Labels
Resolution: Locked This issue was locked by the bot.

Comments

@skleest
Copy link

skleest commented Nov 12, 2015

I am working on an 'invite friends' list using ListView. When I click on a friend, a button next to his/her name should toggle active/inactive.

I am fetching a friends list API as initial dataSource. When a friend is clicked, I am taking the particular rowData (an object) and setting a property of 'invited: true', then re-cloning the dataSource. The button next to the friend's name should re-render depending on the property of friend.invited, but renderRow function in ListView is not running; only the render() function is running. It seems like Listview is not recognizing that data has changed because I only updated a property of an object in an array. I was able to confirm that if the dataSource is an array of strings, not objects, changing the string does indeed re-render the row (as in Facebook's ListView example in UIExplorer).

Is this a bug or is there a workaround? I also asked the question here http://stackoverflow.com/questions/33663461/react-native-listview-row-not-re-rendering-after-state-change/33663737#33663737. Thank you.

@ide
Copy link
Contributor

ide commented Nov 12, 2015

Make sure to create new objects instead of updating the properties of existing objects.

@skleest
Copy link
Author

skleest commented Nov 12, 2015

Thanks for the reply. So if I have an array of objects as datasource, do I have to create a new array, push objects until the object I want to update, rebuild the particular object by creating a new object and manually pushing properties, then clone the datasource?

@ide
Copy link
Contributor

ide commented Nov 12, 2015

Yeah, that's a good way to do it. Probably would take very few lines of code:

let newArray = oldArray.slice();
newArray[indexToUpdate] = {
  ...oldArray[indexToUpdate],
  field: newValue,
};
let newDataSource = oldDataSource.cloneWithRows(newArray);

@skleest
Copy link
Author

skleest commented Nov 12, 2015

That indeed worked, thank you very much!

@skleest skleest closed this as completed Nov 12, 2015
@orelzion
Copy link

orelzion commented Jun 1, 2016

Will that ever be fixed in a more elegant way?

@brianinator
Copy link

Yeah. I find this to be tad dirty as well. It's does only render the row that was affected. I had previously empty the datasource then repopulated so I appreciate this solution better than I had.

@perrosnk
Copy link

@ide If a field in the object in the array is an array, how can I push an item? Do I need apply slice() there too? Could you please share how the previous code would be?

@sshymko
Copy link

sshymko commented Nov 3, 2016

The workaround by @ide defeats the purpose of rowHasChanged, doesn't it? Isn't the idea to pass new rows and let the component determine (via rowHasChanged) ones that have changed significantly enough to be re-rendered?

@shrutic
Copy link
Contributor

shrutic commented Nov 23, 2016

@sshymko . It does seem like the rowHasChanged is still valid. After following the suggestion by @ide, I see the console.log inside render row being called only for the changed items

@ide
Copy link
Contributor

ide commented Nov 23, 2016

@sshymko The approach I pasted allows your rowHasChanged function to be very simple and very fast. By treating the row objects as immutable objects and always creating new ones instead of mutating existing ones, the rowHasChanged implementation can simply be:

rowHasChanged: (r1, r2) => r1 !== r2

@ThomasXu18
Copy link

@ide thank you very much!

@facebook facebook locked as resolved and limited conversation to collaborators Jul 20, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 20, 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

9 participants