React-window: `render` function called but row is not updated until user scrolls

Created on 17 Jan 2019  ·  6Comments  ·  Source: bvaughn/react-window

Hello (again)

Ticket title is long but tells already a lot. I have interactive elements inside the list rows, like a favorite icon. When clicking/tapping this icon, the props are properly updated, the render function is called, but the row isn't updated until the list is scrolled.

You can see it in action here: http://ph-dev.mobile-spot.com

Is this something you are familiar with? or am I doing something wrong?

Initially there was :

  • props:

    • favorites

    • items

1) In the row renderer function I would check if item.id is in favorites. In this case when the user interacts with a favorite icon, only the prop favorites is updated, render function is called.

2) Then I tried something else. I removed the prop favorites, and upstream in the reducer I set the isFavorite property directly on each item. In this case when the user interacts with a favorite icon, the prop items is updated (without mutation), and render function is called. The result is the same. It is only when the list is scrolled that the row is updated.

Do you have any tip/advice?

💬 question

Most helpful comment

I don't really have the time to dig through live production app source code for GitHub questions 😄 I usually ask for smaller repro cases. In this case, since you provided source for list/item, I'll take a stab at it.

When clicking/tapping this icon, the props are properly updated, the render function is called, but the row isn't updated until the list is scrolled.

Which "render function" is called? I assume you mean the one inside of your _List component (which renders the react-window FixedSizeList).

FixedSizeList is a pure component, meaning that it doesn't re-render unless its props change. In the case of a click, you aren't passing any new props to the list, so it doesn't know that it needs to re-render.

The solution I would typically recommended for this– (to fix the re-rendering and to remove the extra rowRenderer wrapper component you have around every item)– is to use the itemData prop mentioned in the docs to pass data directly to your item renderers. In your case, it looks like it might be expensive to pre-compute that data though, so you'll have to decide for yourself whether it's worth doing.

I don't even see where/what is updating isFavorite from the two components you linked to, so I'm not sure how you would implement this exactly either– but the general idea would be that you need to pass an itemData value to FixedSizeList that changes when favorite changes, so it knows to r-render 😄

Hope this helps and good luck!

All 6 comments

Going to need to see your code.

@bvaughn Thank you for your blazing fast reactivity.
Source maps are available on the url I mentioned, see components/list/List.js
Is it helpful enough?

I can also attach some files here (simply rename extension .txt ➝ .js):

The list component:
List.txt

The row component:
ListElement.txt

I don't really have the time to dig through live production app source code for GitHub questions 😄 I usually ask for smaller repro cases. In this case, since you provided source for list/item, I'll take a stab at it.

When clicking/tapping this icon, the props are properly updated, the render function is called, but the row isn't updated until the list is scrolled.

Which "render function" is called? I assume you mean the one inside of your _List component (which renders the react-window FixedSizeList).

FixedSizeList is a pure component, meaning that it doesn't re-render unless its props change. In the case of a click, you aren't passing any new props to the list, so it doesn't know that it needs to re-render.

The solution I would typically recommended for this– (to fix the re-rendering and to remove the extra rowRenderer wrapper component you have around every item)– is to use the itemData prop mentioned in the docs to pass data directly to your item renderers. In your case, it looks like it might be expensive to pre-compute that data though, so you'll have to decide for yourself whether it's worth doing.

I don't even see where/what is updating isFavorite from the two components you linked to, so I'm not sure how you would implement this exactly either– but the general idea would be that you need to pass an itemData value to FixedSizeList that changes when favorite changes, so it knows to r-render 😄

Hope this helps and good luck!

Damn, what a fool. It was feeling so obvious that the react-window List component was taking the items as a prop, but it doesn't! facepalm
Thank you for your time!

😄 It's fine. This was a super common question for react-virtualized, so much so that I added it to the README https://github.com/bvaughn/react-virtualized#pure-components

Maybe I should do the same here.

Thanks for the example using itemData, it works like a charm and I've learnt something new.
All the best. Cheers

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vinnymac picture vinnymac  ·  3Comments

davalapar picture davalapar  ·  3Comments

janhesters picture janhesters  ·  3Comments

delateurj picture delateurj  ·  3Comments

migueloller picture migueloller  ·  3Comments