facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
117.77k stars 24.16k forks source link

FlatList doesnot load data after the initialNumToRender count exceeds. #36766

Open ReactRaylogic opened 1 year ago

ReactRaylogic commented 1 year ago

Description

If the initial state of list is empty and it fills in componentDidMount the flatlsit will only render first 10 items from the list of 60. It doenot renders the item after the initialNumToRender count.

React Native Version

0.71.5

Output of npx react-native info

System: OS: macOS 12.6 CPU: (6) x64 Intel(R) Core(TM) i5-8500B CPU @ 3.00GHz Memory: 37.58 MB / 8.00 GB Shell: 5.8.1 - /bin/zsh Binaries: Node: 18.13.0 - /usr/local/bin/node Yarn: Not Found npm: 8.19.3 - /usr/local/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman Managers: CocoaPods: 1.11.3 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: DriverKit 22.2, iOS 16.2, macOS 13.1, tvOS 16.1, watchOS 9.1 Android SDK: Not Found IDEs: Android Studio: 4.1 AI-201.8743.12.41.6953283 Xcode: 14.2/14C18 - /usr/bin/xcodebuild Languages: Java: 11.0.17 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: 18.2.0 => 18.2.0 react-native: 0.71.1 => 0.71.1 react-native-macos: Not Found npmGlobalPackages: react-native: Not Found

Steps to reproduce

class MyRoomsScreen extends Component {
constructor(){
super()
this.state = {
data: []
}
componentDidMount(){
loadData()
}

loadData(){
let roomArray = []
for(let i =0; i<30;i++){
roomArray.push({id: i+1; name: `Room ${i+1}` })
}
this.setState({data: roomArray})
}

renderRoomList =({item, index}) => {
return(<Text>{item.name} </Text>)
}

render(){
return(
<View>
<FlatList data={this.state.data} renderItem={this.renderRoomList}   />
</View>
)}

Snack, code example, screenshot, or link to a repository

...

github-actions[bot] commented 1 year ago
:warning: Newer Version of React Native is Available!
:information_source: You are on a supported minor version, but it looks like there's a newer patch available. Please upgrade to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases.
dmregister commented 1 year ago

I am having this same issue and was able to create a snack showing the behavior. Moving the slider or typing in the input field will update the state and cause the FlatList to re-render. Notice that the FlatList sometimes renders only the initialNumToRender and nothing after that.

Expo installs RN 0.70.4 but we initially noticed this when upgrading to RN 0.71.6

Snack: https://snack.expo.dev/wsw-_9se4

Screen Recording showing the behavior: flatlist-behavior

NickGerleman commented 1 year ago

Would need to be debuged, but a likely culprit for why the list wouldn't render content beyond initial is that InteractionManager is in a starved state and scheduled work is never run https://reactnative.dev/docs/interactionmanager

douzal34 commented 1 year ago

I have done an upgrade from RN 0.67.3 to RN 0.71.4 few days ago and i got the same result. Same with a downgrade to 0.69.9. If no initialNumToRender is set, flatList is working fine but you have to render 10 items on the launch, not the best way. When initialNumToRender is set and we exceed the number defined, it render but nothing appear on the screen so blank screen so i think it's the same issue.

ReactRaylogic commented 1 year ago

So what i saw is if i have the list in the constructor itself rather than an empty array Flatlist works as expected but if i have an empty list in constructor and updates the list in componentDidmount/useEffect it only renders the item till initialNumToRender count.

izuutech commented 1 year ago

I have done an upgrade from RN 0.67.3 to RN 0.71.4 few days ago and i got the same result. Same with a downgrade to 0.69.9. If no initialNumToRender is set, flatList is working fine but you have to render 10 items on the launch, not the best way. When initialNumToRender is set and we exceed the number defined, it render but nothing appear on the screen so blank screen so i think it's the same issue.

I have this issue too. When I set initialNumToRender={0} it renders blank. And doesn't update later

douzal34 commented 1 year ago

I was with the same issue few weeks ago but with 0.71.6 and even 0.71.7 with the fix of Hermes in debug mode, everything's working fine. Give a try guys, my app SoSkills on store is working on 0.71.7 with initialNumToRender to 3 and no blank screen after this value.

anhkieet commented 1 year ago

I am having the same issue, it doesn't load data after initialNumToRender count exceeds.

foloinfo commented 1 year ago

I had the same problem with SectionList. In my case, the problem was that I forgot to clear the InteractionManager after createInteractionHandle(). I am using react-native 0.71.6 with Expo 48.

@NickGerleman Thanks for your comment about the InteractionManager. I didn't realise it blocked the FlatList behaviour.

ReactRaylogic commented 1 year ago

What i have noticed is it does not rerender if it has empty list in the constructor. If the list is filled in constructor itself 2 rerender happens and FlatList works perfectly.

vietnd2307 commented 10 months ago

I encouter this issue sometimes. My flatlist render inside modal, when modal open, sometimes the list does not render item after initialNumToRender

imamrobani commented 9 months ago

in my case for the first time, all the data was successfully rendered, but when I tried to go back until I exited the application and opened it again, only 10 data were displayed, and there was an empty space below, no data was displayed, but when I killed the app and opened it again, all of them running back to normal

I don't know why this is, this happened when I updated to React Native 0.71.13 (I update using React Native Upgrade Helper) so now I still stay at RN 0.70.13 Previously I was using version 69.3

Has anyone experienced something similar in RN 0.71.XX?

hardikamber commented 9 months ago

We are using RN 0.71.8 and we are facing same issue sometimes list renders items beyond initialNumToRender and sometimes it does not it is quite a weird behaviour is there any solution to solve this??

andreialecu commented 9 months ago

Started running into this after updating to RN 0.72.6, which is the latest version as of today.

Something got broken in FlatLists recently. It's intermittent, and I'm noticing it mainly in production, not in debug mode. Seems to be more common after resuming the app from background, or after navigation (using react-navigation). iOS 17, iPhone 15 Pro Max, if it matters.

raviraj-tudip commented 9 months ago

We have updated the react-native to 0.71.13 after that same issue is happening. Sometime scroll is not working, sometime all items are not rendering. These are all happening due to "initialScrollIndex" props. Please provide any solutions for it.

elbadrawy commented 9 months ago

anyone solved this issue it has been 5 months now it seems that the only solution till now is to not send empty data in the initial render to (flatlist/sectionlist) which will break the ListEmptyComponent behaviour

imamrobani commented 9 months ago

anyone solved this issue it has been 5 months now it seems that the only solution till now is to not send empty data in the initial render to (flatlist/sectionlist) which will break the ListEmptyComponent behaviour

my render not empty, but back until exit app and open again this happen. but if I killed the app and opened it again, all of them running back to normal

elbadrawy commented 9 months ago

I have fixed this issue for my case and am sharing this if anyone has the same issue our issue was that interactionManager was blocked due to animation and other interactions looped in the background how do you identify that issue related to interactionManager put this log on your screen

InteractionManager.runAfterInteractions(() => console.log("running")

if you didn't get the log that's mean you have something blocking flatlist/sectionlist from loading more items however, after we identify the issue we go across all the app even in node_modules, and disable all animation and interactionManager also panresponder

and trying the sectionlist and all working fine

so for our issue, we starting to return all animation peace by peace to find what exactly blocking and we have found 2 issues caused this problem

1- ShimmerPlaceholder package we are using without sending isInteraction={false} 2- we are having logic depend on PanResponder across all the app to calculate the user's inactive/active time so on onStartShouldSetPanResponderCapture and onPanResponderGrant based on your logic you should access the interactive handler by yourself and terminate it

example to get the panresponder handler and kill it

handle = React.createRef()
 onStartShouldSetPanResponderCapture: () => {
                this.handle.current =  this._panResponder.getInteractionHandle()
                //logic
                this.handle.current !== null && InteractionManager.clearInteractionHandle(this.handle.current);
                return false;
        }

I think react-native should implement a way at least to warn developers that there are other interactive running and blocking (flatlist/sectionlist) to do it's job

andreialecu commented 9 months ago

In my case, I replaced the FlatLists with FlashLists.

I looked for stuck interactions but couldn't find anything. Maybe some third-party library that we're using got broken recently, but it's hard to tell.

jianxinzhoutiti commented 9 months ago

+1 I encouter this issue

jianxinzhoutiti commented 9 months ago

{this.state.list && this.state.list.length > 0 ? <SectionList style={{flex: 1, zIndex: -5}} bounces={true} sections={this.state.list} renderSectionHeader={this._renderSection} renderItem={this._renderItem} keyExtractor={(item, index) => item?.id + index} stickySectionHeadersEnabled={true} stickyHeaderIndices={[1]} showsVerticalScrollIndicator={false} ListHeaderComponent={<View style={{height: 1, width: 1,}}/>} ListFooterComponent={<View style={{height: 1, width: 1,}}/>} /> : null} refresh the data twice to display all the data, refresh the data once to display 10 pieces of data only Load pages image image

ReactRaylogic commented 9 months ago

@jianxinzhoutiti Thats how list work in Rn if you don't pass an initialNumberToRender props it will take its default value which is 10. and in the next rerender which is on componentDidMount it will render all the list item.

jianxinzhoutiti commented 9 months ago

@jianxinzhoutiti这就是列表在 Rn 中的工作方式,如果您不传递 initialNumberToRender 属性,它将采用默认值 10。并且在 componentDidMount 上的下一个重新渲染中,它将渲染所有列表项。

I just open and close the page,The expectations should show all the data,But a few times it's only 10 items

cauyyl commented 8 months ago

@jianxinzhoutiti这就是列表在 Rn 中的工作方式,如果您不传递 initialNumberToRender 属性,它将采用默认值 10。并且在 componentDidMount 上的下一个重新渲染中,它将渲染所有列表项。

I just open and close the page,The expectations should show all the data,But a few times it's only 10 items

之前data长度为0的时候不渲染list,还挺稳定的,最近又不太行了,会频发只渲染10个。 I have fixed this problem with {data?.length>0?<FlatList /> : null}, but recently, it has occurred frequently.

Aryk commented 8 months ago

This is really quite a serious issue that's preventing data from loading for users. I'm on 0.72.4, and my guess is it's not fixed even on 0.72.6.

The "hack" right now is to switch key on the flatlist so that it completely re-renders but it's such a hack! This way your ListEmptyComponent will work and you don't have to refactor too much once this actually does get fixed.

  key: data?.length || disabled ? key : `${key}-onEndReachedFix`,

Something like this.

iMonk777 commented 6 months ago

Hi There, I made a fix for this issue. Hope it will help you. The issue is not because of the of the FlatList component, but because InteractionManager.runAfterInteractions() function seems broken for a while already. As there doesn't seem to be any fix coming soon, I prepared a patch to bypass this function when re-rendering the FlatList cells. As far as I understand, the function is there to wait for the rendering, until the user releases the finger from the screen. With this patch, the re-rendering will be done even if the finger is still touching the screen.

File: node_modules/@react-native/virtualized-lists/Interaction/Batchinator.js Change from this:

  schedule() {
    if (this._taskHandle) {
      return;
    }
    const timeoutHandle = setTimeout(() => {
      this._taskHandle = InteractionManager.runAfterInteractions(() => {
        // Note that we clear the handle before invoking the callback so that if the callback calls
        // schedule again, it will actually schedule another task.
        this._taskHandle = null;
        this._callback();
      });
    }, this._delay);
    this._taskHandle = {cancel: () => clearTimeout(timeoutHandle)};
  }

into this:

 schedule(renderWithoutInteractions_patch) {
    if (this._taskHandle) {
      return;
    }
    const timeoutHandle = setTimeout(() => {
            if(renderWithoutInteractions_patch){
                  // Note that we clear the handle before invoking the callback so that if the callback calls
                  // schedule again, it will actually schedule another task.
                  this._taskHandle = null;
                  this._callback();
              }else{
                this._taskHandle = InteractionManager.runAfterInteractions(() => {
                  // Note that we clear the handle before invoking the callback so that if the callback calls
                  // schedule again, it will actually schedule another task.
                  this._taskHandle = null;
                  this._callback();
                });
              }
    }, this._delay);
    this._taskHandle = {cancel: () => clearTimeout(timeoutHandle)};
  }

file: node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.js, Search for the function: _scheduleCellsToRenderUpdate, and change from this:

      } else {
      this._updateCellsToRenderBatcher.schedule();
    }

into this:

       } else {
      this._updateCellsToRenderBatcher.schedule(this.props.renderWithoutInteractions_patch);
   }

file: node_modules/@react-native/virtualized-lists/Lists/VirtualizedList.d.ts Add the prop type and proper docs: Look for the updateCellsBatchingPeriod prop, and add the renderWithoutInteractions_patch prop type after it, together with the comment.

   /**
   * Amount of time between low-pri item render batches, e.g. for rendering items quite a ways off
   * screen. Similar fill rate/responsiveness tradeoff as `maxToRenderPerBatch`.
   */
  updateCellsBatchingPeriod?: number | undefined;

  /**
   * Only use this prop when having re-rendering issuess.
   * This prop will disable the runAfterInteractions inside the .schedule method, inside the Batchinator file.
   * Use this prop carefully :) 
   */
  renderWithoutInteractions_patch?: boolean | undefined;

last change: add the patch prop to your FlatList.

 <FlatList
    renderWithoutInteractions_patch <----- Add this prop. Only use it for the FlatLists that have issues
    style={styles.flatlist}
    contentContainerStyle={styles.flatlistContent}
    the rest of your code

finally, you can make a patch for this fix, using patch-package

pierroo commented 6 months ago

thank you @iMonk777 for this investigation, it's rather surprising this issue with such a basic component is not taken seriously by react native team :/

does your patch have any unexpected side effect? or performance issue?

it's rather hard to test it and confirm of how well it works since the issue just happens randomly and is hard to replicate

iMonk777 commented 6 months ago

No worries @pierroo :) I've been using the patch for around 6 months now, in three different projects, and I didn't have any performance issues or any other issues due to the patch(like crashes). The only thing I found strange, when patching it on my latest project, I couldn't patch it properly until I manually added the dependency in the package.json like so:

image

It seems that npx patch-package was not happy with patching a peer dependency of react-native, if it was not added to the package.json. I'm not sure though how it worked in the past, for my other two projects ^.^

pierroo commented 6 months ago

@lunaleaps if you happen to pass by, what do you think of it? worth being merged into RN virtualized list? FlatList have really become a risky / broken components lately

EDIT: I can confirm your patch fixes the issue! It's wild that react native has such a core issue that's been around for so long :/

pierroo commented 6 months ago

quick question if you don't mind @iMonk777 you said "finally, you can make a patch for this fix, using patch-package"

=> which command did you use? you patched packaged @react-native entirely? or does patch packaging @react-native/virtualized-lists should be the way to go? (I didnt know we could patch package subfolder of libraries?)

iMonk777 commented 6 months ago

I checked the dependency @react-native/virtualized-lists of react-native, to see the correct version. For this, go to node_modules/react-native/package.json, then look for the @react-native/virtualized-lists. copy the entire line and add it in the dependencies object of your package.json.

Make the changes you need(from my initial message), then run npx patch-package @react-native/virtualized-lists.

It doesn't seem to be a package just called @react-native instead there are a bunch of packages with this name, so they are added to this folder.

image
iMonk777 commented 6 months ago

Or you can try adding my patch, but I tihnk you need to change the name of the file, to match the version of RN used in your project @pierroo @react-native+virtualized-lists+0.72.8.patch

pierroo commented 6 months ago

awesome, thanks for the detailed explaination. I'm just gonna use your patch, but then are we sure just changing the file version in the name won't break? like in your files there are lines number involved etc for patch package to know where to look for; so IF virtualized list had any change between 0.72.8 and 0.73.4, that probably will break.

(although most probably such a core component wasn't touched in between)

fcole90 commented 5 months ago

@iMonk777 Your patch looks great! Are you planning to create a PR for it to be merged? 😊

ZYongjie commented 5 months ago

initialNumToRender should be enough to fill the screen but not much more.In my case, the height of item is too small, so I set initialNumToRender={30} to fill the screen.

changwoolab commented 4 months ago

In my case, using Animated so frequently leads to not loading more items. Because animation fills the interactionSet of InteractionManager, callbacks cannot be run forever.

So, I patched @iMonk777 's solution because I needed to animate my component anyway

striwensko commented 4 months ago

For people still having issues you might want to check your elements aren't using margin. That makes the flat list buggy sometimes it works sometimes it doesn't without any kind of logical reason. It was failing to render properly around 20% of the time but without using margins and replacing them for padding it works perfectly all the time.

rioaguspermana commented 3 months ago

initialNumToRender should be enough to fill the screen but not much more.In my case, the height of item is too small, so I set initialNumToRender={30} to fill the screen.

thank you for this, in my case, I realized my item height is not set.

rsainiWin commented 1 month ago

I was facing the same I was not able to find any solution I had to use the initailNumToRender to all items

adminruparupa commented 1 month ago

in my case onEndReached not trigrered

vhakulinen commented 6 days ago

I was facing the same (or similar) issue - tho' with SectionList. A workaround that seems to work for me is not to render a empty list (while data is loading). Other observations:

EDIT: that workaround has a side effect of unmounting and remounting any header/footer components, which in our case are quite expensive components... EDIT: it looks like that react-navigation's interactions have something to do with this. In BottomTabNavigator, setting the default route to the one where this bug is present fixes the issue and all the items are rendered correctly. Maybe there is something in the bottom tab nav's buttons / navigation events that are blocking the interaction manager? EDIT: and it was some animation code all along that was causing the issue...