This is probably related to #70;
I still have an issue with calculating heights of my items using data,
I used this approach where I tried to use getDataForIndex but nothing rendered on the screen:
this._layoutProvider = new LayoutProvider(
index => {
return "DEFAULT";
},
(type, dim, index) => {
const item = this._dataProvider.getDataForIndex(index);
if (item.media) {
if (item.media.length > 0) {
if (item.media.length === 1) {
dim.width = TabletWidth;
dim.height = 106 + (TabletWidth * (item.media.height / item.media.width));
} else if (item.media.length === 2) {
dim.width = TabletWidth;
dim.height = 106 + (((TabletWidth - 20) / 2) + 8);
} else if (item.media.length === 3) {
dim.width = TabletWidth;
dim.height = 106 + (((TabletWidth - 20) / 2) + (TabletWidth / 2.2) + 8);
} else {
dim.width = TabletWidth;
dim.height = 106 + ((((TabletWidth - 20) / 2) + 8) * 2);
}
}
}
});
then I used this approach and it didn't work like before:
this._layoutProvider = new LayoutProvider(
index => {
return "DEFAULT";
},
(type, dim, item) => {
if (item.media) {
if (item.media.length > 0) {
if (item.media.length === 1) {
dim.width = TabletWidth;
dim.height = 106 + (TabletWidth * (item.media.height / item.media.width));
}
else if (item.media.length === 2) {
dim.width = TabletWidth;
dim.height = 106 + (((TabletWidth - 20) / 2) + 8);
}
else if (item.media.length === 3) {
dim.width = TabletWidth;
dim.height = 106 + (((TabletWidth - 20) / 2) + (TabletWidth / 2.2) + 8);
}
else {
dim.width = TabletWidth;
dim.height = 106 + ((((TabletWidth - 20) / 2) + 8) * 2);
}
}
}
});
I also tested this:
this._layoutProvider = new LayoutProvider(()=>{return "DEFAULT"}, (data, dim)=>{
dim.width = TabletWidth;
dim.height = 106 + (
data.media ?
data.media.length > 0 ?
data.media.length === 1 ?
TabletWidth * (data.media.height / data.media.width)
: data.media.length === 2 ?
((TabletWidth - 20) / 2) + 8
: data.media.length === 3 ?
((TabletWidth - 20) / 2) + (TabletWidth / 2.2) + 8
:
(((TabletWidth - 20) / 2) + 8) * 2
: null : null
)
});
this code only calculates 106 as the height of all items! and ignores all the conditions!
am I missing something here, how can I calculate item height based on item data?
The dim object being passed to you is reused. In case you fail to set it the older value will be used. I think that's what is happening in your case. Use debugger to check if any condition is being hit at all. Also, if computing height is too complicated you can use forceNonDeterministicRendering={true}, it might make your life simpler. Let me know if this helps.
@naqvitalha thanks for the response.
It actually hits all the conditions but apparently it just ignores setting the height for each item, what can be done here?
Also about using forceNonDeterministicRendering, I've already tested that but it does not look good while loading, cause it's determining the height on load and it makes the items kind of jumpy! I mean what should I set for dim.height then? with the last LayoutProvider that I used at first all items heights are 106 and then after a couple of seconds they get their real heights. I tried setting dim.height to 1 (cause 0 didn't work) in order to make the list look clean on load, but it takes some time for them to show up, is there a way to know when the items are fully rendered?
Default mode treats given dimensions as exact, if you're setting them correctly it should work. If you can provide a small repro on expo I can locate the problem. This works as expected in our projects.
Regarding forceNonDeterministicRendering issue, we definitely don't want things to move around, that is not expected and we have put in safeguards for that. Can you make sure you have a shouldComponentUpdate defined and are not running on dev mode?
And finally, giving estimated height as 1 will cause RLV to render lot of items since it would thing it needs more items to fill the screen. That is the slowdown you are seeing.
I didn't have shouldComponentUpdate but I was't running on dev either, I've actually made a snack on expo.
Performance on this snack in actually good, but there's some differences between my project and this repo, the data I've provided on expo is static containing 80 posts that has a lot of photos in it, with different post styles, but on my own project the data is being loaded on mount from server with pagination which means I fetch each page (10 posts) onEndReach; the thing I struggled with was when to define LayoutProvider and DataProvider? cause in your examples data is static and LayoutProvider and DataProvider are defined in the constructor, so I finally put them on the fetch method right after the data is retrieved, but LayoutProvider seemed broken however when I logged on the console they seemed to work!!!
I'm really stuck here, it would be awesome if you could check out the repo?
@Komeyl94 For some reason snack is not working for me. I checked multiple devices. I can look into the repo, no problem. Happy to help :)
Thank you for your help,
The repo had an error which I fixed earlier, now you may be able to run it
However I think the main reason for performance (or more precisely render) issues is lack of rowHasChanged and shouldComponentUpdate which you mentioned earlier or in other issues.
Here's a screenshot from the app, which you can see in multiple posts either the height is not set correctly or the image is not rendered:

This issue only appears on single picture posts, as you can see in the repo the height of other posts are fixed and predefined in styles, but the height for single pictures are calculated on render based on the width and height of the main picture like so:
singleImageHeight: props.media.length === 1 ? TabletWidth * (props.media[0].height / props.media[0].width) : 0,
this is stored in a state in constructor, how can I optimize this rowHasChanged or shouldComponentUpdate?
btw my PostView component is a PureComponent, so should I still use shouldComponentUpdate?
Few things I found wrong with the code:
1) Estimated height was 1 and it needs to be an actual estimate for optimal performance.
2) Instead of having one type called "DEFAULT" have multiple ones backed by their own components. Right now the problem is that you have one big component which renders separate stuff based on conditions why now let rowRenderer choose a component instead. You have some components with just text and if you use the same to render an image the text component will get unmounted ideally you must avoid unnecessary unmounts and promote reuse. That is the point of recycling.
3) You have lot of component level setState which I don't think are necessary, remember they will slow things down. Also, changing things like imageLoaded1 will not re-render a component being reused incase the previous use case also had the same value. That's how recycling works.
More that than you are getting dimensions upfront in your data source. I see thing being too complicated. Can you just try rendering a use case where only one photo is being shown? It'll be easier for me to go through and for you to understand. Just render images, from my side I can assure you that this is a solved use case and we've done it before.
Your page can be much better. Reduce setState calls and break into components and add more types to LayoutProvider
Thanks a lot for this, it really helped 馃憤
Glad to help, closing.
Most helpful comment
Few things I found wrong with the code:
1) Estimated height was 1 and it needs to be an actual estimate for optimal performance.
2) Instead of having one type called "DEFAULT" have multiple ones backed by their own components. Right now the problem is that you have one big component which renders separate stuff based on conditions why now let
rowRendererchoose a component instead. You have some components with just text and if you use the same to render an image the text component will get unmounted ideally you must avoid unnecessary unmounts and promote reuse. That is the point of recycling.3) You have lot of component level
setStatewhich I don't think are necessary, remember they will slow things down. Also, changing things likeimageLoaded1will not re-render a component being reused incase the previous use case also had the same value. That's how recycling works.More that than you are getting dimensions upfront in your data source. I see thing being too complicated. Can you just try rendering a use case where only one photo is being shown? It'll be easier for me to go through and for you to understand. Just render images, from my side I can assure you that this is a solved use case and we've done it before.
Your page can be much better. Reduce
setStatecalls and break into components and add more types toLayoutProvider