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

[FlatList] Sometimes FlatList rows are rendered, but not displayed until scroll. RN 0.43 #13316

Closed
joonhocho opened this Issue Apr 5, 2017 · 78 comments

Comments

Projects
None yet
@joonhocho
Contributor

joonhocho commented Apr 5, 2017

Description

When using FlatList, rows are not displayed though renderItem is called.
Rows appear immediately when scroll is triggered on the list.

Reproduction Steps and Sample Code

export default class List extends Component {
  renderItem({item}) {
    return (
      <Text>{item}</Text>
    );
  }

  render() {
    return (
      <FlatList
        style={{
          flex: 1,
          backgroundColor: 'white',
        }}
        data={[1, 2]}
        renderItem={this.renderItem}
      />
    );
  }
}

Solution

FlatList should always display its rendered items.

Additional Information

  • React Native version: 0.43.0
  • Platform: iOS
  • Development Operating System: MacOS
  • Dev tools: Xcode

@joonhocho joonhocho changed the title from [FlatList] Sometimes rows are rendered, but not displayed until scroll. to [FlatList] Sometimes FlatList rows are rendered, but not displayed until scroll. RN 0.43 Apr 5, 2017

@joonhocho

This comment has been minimized.

Show comment
Hide comment
@joonhocho

joonhocho Apr 5, 2017

Contributor

Related #13202

Contributor

joonhocho commented Apr 5, 2017

Related #13202

@joshjhargreaves

This comment has been minimized.

Show comment
Hide comment
@joshjhargreaves

joshjhargreaves Apr 5, 2017

Collaborator

@joonhocho could you create a gif of this in action? I can't reproduce with your example.

Collaborator

joshjhargreaves commented Apr 5, 2017

@joonhocho could you create a gif of this in action? I can't reproduce with your example.

@joshjhargreaves

This comment has been minimized.

Show comment
Hide comment
@joshjhargreaves

joshjhargreaves Apr 5, 2017

Collaborator

Are you experiencing this issue in a standalone project and/or are you able to reproduce in a standalone project if not?

Collaborator

joshjhargreaves commented Apr 5, 2017

Are you experiencing this issue in a standalone project and/or are you able to reproduce in a standalone project if not?

@Thomas101

This comment has been minimized.

Show comment
Hide comment
@Thomas101

Thomas101 Apr 5, 2017

We're also seeing this issue. Looks like it could be something to do with the FlatList being in a navigator on iOS. Managed to reproduce it in a standalone project. You'll have to excuse the code it's a bit rough.

react-native init and add the following code as your index.ios.js. Once launched, tap on A. Tap remove. Tap back. Then you'll need to scroll to get FlatList to re-render.

We found this on RN0.43.1 iOS simulator, iPad but not android. Seems to work as expected on android

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View, FlatList, TouchableOpacity, Navigator } from 'react-native';

let data = [ { id: 'a' }, { id: 'b' }, { id: 'c' } ]
let listeners = []

class List extends Component {
  constructor (props) {
    super(props)
    this.state = { data: Array.from(data) }
  }

  componentDidMount () {
    listeners.push(() => { this.setState({ data: data }) })
  }

  render () {
    return (
      <FlatList
        data={this.state.data}
        keyExtractor={(item) => item.id}
        renderItem={({item}) => (
          <TouchableOpacity onPress={() => this.props.navigator.push({ id: 'r2', item: item })}>
            <View>
              <Text>{item.id}</Text>
              <Text>{item.id}</Text>
              <Text>{item.id}</Text>
              <Text>{item.id}</Text>
            </View>
          </TouchableOpacity>
        )}
      />
    )
  }
}

export default class AwesomeProject extends Component {

  renderScene (route, navigator) {
    if (route.id === 'r1') {
      return (<List navigator={navigator} />)
    } else if (route.id === 'r2') {
      return (
        <View>
          <Text>{route.item.id}</Text>
          <TouchableOpacity onPress={() => {
            data = [data[0], data[2]]
            listeners.forEach((l) => { l() })
          }}>
            <Text>Remove</Text>
          </TouchableOpacity>
          <TouchableOpacity onPress={() => navigator.pop()}>
            <Text>Back</Text>
          </TouchableOpacity>
        </View>
      )
    }
  }

  render() {
    return (
      <View style={[StyleSheet.absoluteFill, { paddingTop: 50 }]}>
        <Navigator initialRoute={{ id: 'r1' }} renderScene={this.renderScene.bind(this)} />
      </View>
    );
  }
}

AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);

We're also seeing this issue. Looks like it could be something to do with the FlatList being in a navigator on iOS. Managed to reproduce it in a standalone project. You'll have to excuse the code it's a bit rough.

react-native init and add the following code as your index.ios.js. Once launched, tap on A. Tap remove. Tap back. Then you'll need to scroll to get FlatList to re-render.

We found this on RN0.43.1 iOS simulator, iPad but not android. Seems to work as expected on android

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View, FlatList, TouchableOpacity, Navigator } from 'react-native';

let data = [ { id: 'a' }, { id: 'b' }, { id: 'c' } ]
let listeners = []

class List extends Component {
  constructor (props) {
    super(props)
    this.state = { data: Array.from(data) }
  }

  componentDidMount () {
    listeners.push(() => { this.setState({ data: data }) })
  }

  render () {
    return (
      <FlatList
        data={this.state.data}
        keyExtractor={(item) => item.id}
        renderItem={({item}) => (
          <TouchableOpacity onPress={() => this.props.navigator.push({ id: 'r2', item: item })}>
            <View>
              <Text>{item.id}</Text>
              <Text>{item.id}</Text>
              <Text>{item.id}</Text>
              <Text>{item.id}</Text>
            </View>
          </TouchableOpacity>
        )}
      />
    )
  }
}

export default class AwesomeProject extends Component {

  renderScene (route, navigator) {
    if (route.id === 'r1') {
      return (<List navigator={navigator} />)
    } else if (route.id === 'r2') {
      return (
        <View>
          <Text>{route.item.id}</Text>
          <TouchableOpacity onPress={() => {
            data = [data[0], data[2]]
            listeners.forEach((l) => { l() })
          }}>
            <Text>Remove</Text>
          </TouchableOpacity>
          <TouchableOpacity onPress={() => navigator.pop()}>
            <Text>Back</Text>
          </TouchableOpacity>
        </View>
      )
    }
  }

  render() {
    return (
      <View style={[StyleSheet.absoluteFill, { paddingTop: 50 }]}>
        <Navigator initialRoute={{ id: 'r1' }} renderScene={this.renderScene.bind(this)} />
      </View>
    );
  }
}

AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
@sahrens

This comment has been minimized.

Show comment
Hide comment
@sahrens

sahrens Apr 5, 2017

Contributor

Does setting removeClippedSubviews={false} fix the issue? Sounds like the issue might be related to the navigator which would explain why we don't see this problem at Facebook. cc @shergin

Contributor

sahrens commented Apr 5, 2017

Does setting removeClippedSubviews={false} fix the issue? Sounds like the issue might be related to the navigator which would explain why we don't see this problem at Facebook. cc @shergin

@joonhocho

This comment has been minimized.

Show comment
Hide comment
@joonhocho

joonhocho Apr 5, 2017

Contributor

@Thomas101 @sahrens I am using react-navigation for your information.

Contributor

joonhocho commented Apr 5, 2017

@Thomas101 @sahrens I am using react-navigation for your information.

@raffij

This comment has been minimized.

Show comment
Hide comment
@raffij

raffij Apr 5, 2017

@sahrens removeClippedSubviews={false} works for us for now.

We are using Navigator for a tab based app.

  1. Navigate to the flatlist scene. List shows.
  2. Navigate to another tab.
  3. Make a change which affects the flatlist scene.
  4. Navigate to the already mounted flatlist scene.
  5. Flatlist shows as empty.
  6. Touch component and the items are made visible.

raffij commented Apr 5, 2017

@sahrens removeClippedSubviews={false} works for us for now.

We are using Navigator for a tab based app.

  1. Navigate to the flatlist scene. List shows.
  2. Navigate to another tab.
  3. Make a change which affects the flatlist scene.
  4. Navigate to the already mounted flatlist scene.
  5. Flatlist shows as empty.
  6. Touch component and the items are made visible.
@joonhocho

This comment has been minimized.

Show comment
Hide comment
@joonhocho

joonhocho Apr 6, 2017

Contributor

@raffij @sahrens It also fixed the issue for me as well.

Contributor

joonhocho commented Apr 6, 2017

@raffij @sahrens It also fixed the issue for me as well.

@Thomas101

This comment has been minimized.

Show comment
Hide comment
@Thomas101

Thomas101 Apr 6, 2017

removeClippedSubviews={false} works for us too. I noticed in the VirtualizedList docs there's some discussion around setting this as the default, could I +1 that as I imagine quite a few people will come up against this?

removeClippedSubviews={false} works for us too. I noticed in the VirtualizedList docs there's some discussion around setting this as the default, could I +1 that as I imagine quite a few people will come up against this?

@sahrens

This comment has been minimized.

Show comment
Hide comment
@sahrens

sahrens Apr 6, 2017

Contributor

I'm running an experiment in production soon to see the effect on scroll perf. If the hit isn't too bad, we'll turn it off by default.

Contributor

sahrens commented Apr 6, 2017

I'm running an experiment in production soon to see the effect on scroll perf. If the hit isn't too bad, we'll turn it off by default.

@huyanhh

This comment has been minimized.

Show comment
Hide comment
@huyanhh

huyanhh Apr 7, 2017

Contributor

Running into a similar problem here. It isn't exactly scrolling that's my problem though. What I have is a horizontal FlatList with paging enabled. I have a function that adjusts each item of the list to the width of the screen. What I'm doing right now is using redux and async storage to persist all my items, but the items do not render until I hit a button in my view to add another item in the list. When I set removeClippedSubviews={false} the view renders, but only part of it. I suspect it has something to do with the render prop, because when I render just a TextView I see the display, but not when I render my full custom component. I'll post my code and a video tomorrow.

Contributor

huyanhh commented Apr 7, 2017

Running into a similar problem here. It isn't exactly scrolling that's my problem though. What I have is a horizontal FlatList with paging enabled. I have a function that adjusts each item of the list to the width of the screen. What I'm doing right now is using redux and async storage to persist all my items, but the items do not render until I hit a button in my view to add another item in the list. When I set removeClippedSubviews={false} the view renders, but only part of it. I suspect it has something to do with the render prop, because when I render just a TextView I see the display, but not when I render my full custom component. I'll post my code and a video tomorrow.

@joenoon

This comment has been minimized.

Show comment
Hide comment
@joenoon

joenoon Apr 9, 2017

Contributor

I had a possibly related issue with a ListView (RN 0.43.2) that seems to be solved by the removeClippedSubviews={false} suggestion.

In my case this ListView was inside an Animated.View with a translateY style (sliding down). When the animation ended the ListView would have variable space above the first row (as if there was some contentInset padding). Just barely scrolling the list would snap everything back to normal and the first row would be correctly at the top.

Just noting it here in case it might provide a hint.

Contributor

joenoon commented Apr 9, 2017

I had a possibly related issue with a ListView (RN 0.43.2) that seems to be solved by the removeClippedSubviews={false} suggestion.

In my case this ListView was inside an Animated.View with a translateY style (sliding down). When the animation ended the ListView would have variable space above the first row (as if there was some contentInset padding). Just barely scrolling the list would snap everything back to normal and the first row would be correctly at the top.

Just noting it here in case it might provide a hint.

@sahrens

This comment has been minimized.

Show comment
Hide comment
@sahrens

sahrens Apr 13, 2017

Contributor

I'm putting in a diff to disable removeClippedSubviews by default in VirtualizedList, so it will be opt-in and hopefully won't bite people like this in the future.

Contributor

sahrens commented Apr 13, 2017

I'm putting in a diff to disable removeClippedSubviews by default in VirtualizedList, so it will be opt-in and hopefully won't bite people like this in the future.

@joonhocho

This comment has been minimized.

Show comment
Hide comment
@joonhocho

joonhocho Apr 13, 2017

Contributor

@sahrens Could you explain why removeClippedSubviews fixes the issue? Is setting removeClippedSubviews as false an optimal solution or is it just a temporary quick fix?

Because I am using other RN libraries like react-native-sortable-listview that suffers from the similar issue (rows not appearing until initial scroll) even though it uses ListView, not FlatView. Thus, I guess it's not only limited to FlatList, but also affect other types of scroll views as well. When I manually set removeClippedSubviews={false}, it fixes the issue, but also causes some unwanted side effects.

Contributor

joonhocho commented Apr 13, 2017

@sahrens Could you explain why removeClippedSubviews fixes the issue? Is setting removeClippedSubviews as false an optimal solution or is it just a temporary quick fix?

Because I am using other RN libraries like react-native-sortable-listview that suffers from the similar issue (rows not appearing until initial scroll) even though it uses ListView, not FlatView. Thus, I guess it's not only limited to FlatList, but also affect other types of scroll views as well. When I manually set removeClippedSubviews={false}, it fixes the issue, but also causes some unwanted side effects.

@Noitidart

This comment has been minimized.

Show comment
Hide comment
@Noitidart

Noitidart Apr 14, 2017

Could you explain why removeClippedSubviews fixes the issue?

I am wodering this question as well. I am using react-navigation as well. Setting removeClippedSubviews to false also fixed this for me. I'm not sure of it's implications (reduced perf?).

Could you explain why removeClippedSubviews fixes the issue?

I am wodering this question as well. I am using react-navigation as well. Setting removeClippedSubviews to false also fixed this for me. I'm not sure of it's implications (reduced perf?).

Maxwell2022 pushed a commit to Maxwell2022/react-native that referenced this issue Apr 19, 2017

disable removeClippedSubviews by default
Summary:
It's just causing problems (e.g. when combined with transform animations like those used
in some navigators) and hopefully it's not necessary with JS-side windowing. If people need the
perf, they can turn it on themselves.

Should fix facebook#13316 and related issues.

Reviewed By: achen1

Differential Revision: D4884147

fbshipit-source-id: 95c82448581076c0d0b2c80b1cd80cc294898174
@npomfret

This comment has been minimized.

Show comment
Hide comment
@npomfret

npomfret Apr 28, 2017

Contributor

I'm getting this too in RN 0.43.3. Why is this closed?

Contributor

npomfret commented Apr 28, 2017

I'm getting this too in RN 0.43.3. Why is this closed?

@joshjhargreaves

This comment has been minimized.

Show comment
Hide comment
@joshjhargreaves

joshjhargreaves Apr 28, 2017

Collaborator

I think the conclusion is that setting removeClippedSubviews={false} seems to fix these issues? Have you tried this yet?

Collaborator

joshjhargreaves commented Apr 28, 2017

I think the conclusion is that setting removeClippedSubviews={false} seems to fix these issues? Have you tried this yet?

@npomfret

This comment has been minimized.

Show comment
Hide comment
@npomfret

npomfret Apr 28, 2017

Contributor

Yeah, i just figured that out, cheers. Much better. But it's still a bug, no?

Contributor

npomfret commented Apr 28, 2017

Yeah, i just figured that out, cheers. Much better. But it's still a bug, no?

@sahrens

This comment has been minimized.

Show comment
Hide comment
@sahrens

sahrens Apr 28, 2017

Contributor

removeClippedSubviews is now off by default in master.

Contributor

sahrens commented Apr 28, 2017

removeClippedSubviews is now off by default in master.

@vjeranc

This comment has been minimized.

Show comment
Hide comment
@vjeranc

vjeranc May 4, 2017

Contributor

This also breaks components like MapView in react-native-maps (the map gets frozen on some area until swipe or some other gesture event). So, this is not just an issue with react-native components.

Adding removeClippedSubviews={false} does not work there (even when going to the deepest React.Component.

Contributor

vjeranc commented May 4, 2017

This also breaks components like MapView in react-native-maps (the map gets frozen on some area until swipe or some other gesture event). So, this is not just an issue with react-native components.

Adding removeClippedSubviews={false} does not work there (even when going to the deepest React.Component.

@huyanhh

This comment has been minimized.

Show comment
Hide comment
@huyanhh

huyanhh May 6, 2017

Contributor

Got something really weird.

I'm trying to scroll to the end of my horizontal pager I made out of the Flatlist with this

componentDidMount() {
    this._listRef.scrollToEnd({ animated: false });
  }

Here's my Flatlist:

<FlatList
          ref={(flatList) => { this._listRef = flatList; }}
          data={this.props.log}
          onLayout={this.adjustPageSize}
          renderItem={this.renderPage}
          showsHorizontalScrollIndicator={false}
          getItemLayout={(data, index) => {
            const width = Dimensions.get('window').width;
            return { length: width, offset: width * index, index };
          }}
          removeClippedSubviews
          horizontal
          pagingEnabled
          directionalLockEnabled
        />

When I make it like this, my list does not render until I scroll, but when I change getItemLayout to this:

 getItemLayout={(data, index) => {
            const width = Dimensions.get('window').width;
            return { length: 0, offset: width * index, index };
          }}

with the length attribute as 0, my list renders perfectly fine, and it scrolls to the end correctly in componentDidMount

Contributor

huyanhh commented May 6, 2017

Got something really weird.

I'm trying to scroll to the end of my horizontal pager I made out of the Flatlist with this

componentDidMount() {
    this._listRef.scrollToEnd({ animated: false });
  }

Here's my Flatlist:

<FlatList
          ref={(flatList) => { this._listRef = flatList; }}
          data={this.props.log}
          onLayout={this.adjustPageSize}
          renderItem={this.renderPage}
          showsHorizontalScrollIndicator={false}
          getItemLayout={(data, index) => {
            const width = Dimensions.get('window').width;
            return { length: width, offset: width * index, index };
          }}
          removeClippedSubviews
          horizontal
          pagingEnabled
          directionalLockEnabled
        />

When I make it like this, my list does not render until I scroll, but when I change getItemLayout to this:

 getItemLayout={(data, index) => {
            const width = Dimensions.get('window').width;
            return { length: 0, offset: width * index, index };
          }}

with the length attribute as 0, my list renders perfectly fine, and it scrolls to the end correctly in componentDidMount

@sahrens

This comment has been minimized.

Show comment
Hide comment
@sahrens

sahrens May 6, 2017

Contributor

@huyanhh: that is indeed quite weird. Does it work without the length hack and without removeClippedSubviews?

Contributor

sahrens commented May 6, 2017

@huyanhh: that is indeed quite weird. Does it work without the length hack and without removeClippedSubviews?

thotegowda added a commit to thotegowda/react-native that referenced this issue May 7, 2017

disable removeClippedSubviews by default
Summary:
It's just causing problems (e.g. when combined with transform animations like those used
in some navigators) and hopefully it's not necessary with JS-side windowing. If people need the
perf, they can turn it on themselves.

Should fix facebook#13316 and related issues.

Reviewed By: achen1

Differential Revision: D4884147

fbshipit-source-id: 95c82448581076c0d0b2c80b1cd80cc294898174
@huyanhh

This comment has been minimized.

Show comment
Hide comment
@huyanhh

huyanhh May 8, 2017

Contributor

@sahrens The list renders fine no matter what removeClippedSubviews is, as long as length is 0. Once I change back length to the screen width, regardless if removeClippedSubviews is turned off or not my list goes back to being blank until scroll.

Contributor

huyanhh commented May 8, 2017

@sahrens The list renders fine no matter what removeClippedSubviews is, as long as length is 0. Once I change back length to the screen width, regardless if removeClippedSubviews is turned off or not my list goes back to being blank until scroll.

@dzuncoi

This comment has been minimized.

Show comment
Hide comment
@dzuncoi

dzuncoi May 10, 2017

removeClippedSubviews does not work for me, although I'm using a very common FlatList, as below:

<FlatList
   scrollEventThrottle={200}
   onScroll={e => true}
   ref={ref => this.listRef = ref}
   data={this.state.messageList}
   keyExtractor={item => item.messageId}
   removeClippedSubviews={false}
   renderItem={({item, index}) => {
      return (
          <MessageItem item={item}/>
      )
}}/>

Currently, my solution is after retrieving list data, I have to manually scroll down 1px this.listRef.scrollToOffset({offset: 1})

But it's still a bug, I think it should only be closed after fixed by a new release.

dzuncoi commented May 10, 2017

removeClippedSubviews does not work for me, although I'm using a very common FlatList, as below:

<FlatList
   scrollEventThrottle={200}
   onScroll={e => true}
   ref={ref => this.listRef = ref}
   data={this.state.messageList}
   keyExtractor={item => item.messageId}
   removeClippedSubviews={false}
   renderItem={({item, index}) => {
      return (
          <MessageItem item={item}/>
      )
}}/>

Currently, my solution is after retrieving list data, I have to manually scroll down 1px this.listRef.scrollToOffset({offset: 1})

But it's still a bug, I think it should only be closed after fixed by a new release.

@joshjhargreaves

This comment has been minimized.

Show comment
Hide comment
@joshjhargreaves

joshjhargreaves May 11, 2017

Collaborator

@dzuncoi, @huyanhh, do you think you might be able to put together an example project?

Collaborator

joshjhargreaves commented May 11, 2017

@dzuncoi, @huyanhh, do you think you might be able to put together an example project?

@dzuncoi

This comment has been minimized.

Show comment
Hide comment
@dzuncoi

dzuncoi May 11, 2017

@joshyhargreaves will try asap

dzuncoi commented May 11, 2017

@joshyhargreaves will try asap

@sahrens

This comment has been minimized.

Show comment
Hide comment
@sahrens

sahrens May 11, 2017

Contributor

Why are you setting a useless onScroll property and changing the scroll event throttle? I don't think either of those should break anything, but can you double check removing those?

Contributor

sahrens commented May 11, 2017

Why are you setting a useless onScroll property and changing the scroll event throttle? I don't think either of those should break anything, but can you double check removing those?

@dzuncoi

This comment has been minimized.

Show comment
Hide comment
@dzuncoi

dzuncoi May 11, 2017

@sahrens
I just minimized onScroll property in my comment. Remove those properties does not affect anything.
After investigating more, removeClippedSubviews={false} works for me only if I add initialNumToRender={myInitialData.length} either. So my list does not render all items because my initial data size is more than the default number (10) of how many items to render in the initial batch.

Does it worth to emphasize this in FlatList docs?

dzuncoi commented May 11, 2017

@sahrens
I just minimized onScroll property in my comment. Remove those properties does not affect anything.
After investigating more, removeClippedSubviews={false} works for me only if I add initialNumToRender={myInitialData.length} either. So my list does not render all items because my initial data size is more than the default number (10) of how many items to render in the initial batch.

Does it worth to emphasize this in FlatList docs?

@sahrens

This comment has been minimized.

Show comment
Hide comment
@sahrens

sahrens May 11, 2017

Contributor

That shouldn't be a problem - FlatListExample has an initialNumToRender much smaller than the data size with no issue.

Contributor

sahrens commented May 11, 2017

That shouldn't be a problem - FlatListExample has an initialNumToRender much smaller than the data size with no issue.

@dantman

This comment has been minimized.

Show comment
Hide comment
@dantman

dantman May 11, 2017

Contributor

@dzuncoi @sahrens Yes, using initialNumToRender={myInitialData.length} should never be done and is just hiding the issue by breaking FlatList and turning it essentially into a ScrollView.

That line basically disables all of FlatList's optimization intended to only render a portion of the items that are on screen and forces it to just render every single item in your list at once.

Contributor

dantman commented May 11, 2017

@dzuncoi @sahrens Yes, using initialNumToRender={myInitialData.length} should never be done and is just hiding the issue by breaking FlatList and turning it essentially into a ScrollView.

That line basically disables all of FlatList's optimization intended to only render a portion of the items that are on screen and forces it to just render every single item in your list at once.

@dzuncoi

This comment has been minimized.

Show comment
Hide comment
@dzuncoi

dzuncoi May 12, 2017

@dantman

optimization intended to only render a portion of the items that are on screen

So how do FlatList determine how many items will be rendered to fit screen, so that users don't see remaining-not-rendered items, or it just renders 10 items (by default)?
Maybe my problem is now out of this issue's scope.

dzuncoi commented May 12, 2017

@dantman

optimization intended to only render a portion of the items that are on screen

So how do FlatList determine how many items will be rendered to fit screen, so that users don't see remaining-not-rendered items, or it just renders 10 items (by default)?
Maybe my problem is now out of this issue's scope.

@dantman

This comment has been minimized.

Show comment
Hide comment
@dantman

dantman May 12, 2017

Contributor

@dzuncoi AFAICT FlatList uses the normal algorithm for this: Render initialNumToRender items (10), make sure the screen is full of items, if not render initialNumToRender (10) more items until it is, if the user has scrolled do this again to show the newly visible items. Not sure if FlatList does it, but maybe also unmount things that are no longer visible after scroll.

Contributor

dantman commented May 12, 2017

@dzuncoi AFAICT FlatList uses the normal algorithm for this: Render initialNumToRender items (10), make sure the screen is full of items, if not render initialNumToRender (10) more items until it is, if the user has scrolled do this again to show the newly visible items. Not sure if FlatList does it, but maybe also unmount things that are no longer visible after scroll.

@michelalbers

This comment has been minimized.

Show comment
Hide comment
@michelalbers

michelalbers Nov 7, 2017

@Kiarash-Z fix works and greatly improves performance. But why tho?

michelalbers commented Nov 7, 2017

@Kiarash-Z fix works and greatly improves performance. But why tho?

@jslok

This comment has been minimized.

Show comment
Hide comment
@jslok

jslok Nov 27, 2017

This is still an issue in RN 0.49.3 if removeClippedSubviews=true.

jslok commented Nov 27, 2017

This is still an issue in RN 0.49.3 if removeClippedSubviews=true.

@abeddow91

This comment has been minimized.

Show comment
Hide comment
@abeddow91

abeddow91 Nov 29, 2017

I am having this issue still even with removeClippedSubviews={false}. Any additional solutions here?

I am having this issue still even with removeClippedSubviews={false}. Any additional solutions here?

@tasneembohra

This comment has been minimized.

Show comment
Hide comment
@tasneembohra

tasneembohra Nov 30, 2017

I am still having this issue with removeClippedSubviews = {false} but then setting it false also reducing my rendering performance.
However, @douglasjunior solution worked perfectly fine for me without compromising performance.
Thanks @douglasjunior 👍

I am still having this issue with removeClippedSubviews = {false} but then setting it false also reducing my rendering performance.
However, @douglasjunior solution worked perfectly fine for me without compromising performance.
Thanks @douglasjunior 👍

@jslok

This comment has been minimized.

Show comment
Hide comment
@jslok

jslok Nov 30, 2017

#1831
According to that, the fix was merged in and available for RN 0.50. If you do not want to or cannot upgrade RN yet, you can just change the line as shown in this file.
03ae65b

On my app, this fix solves the issue and I can still use removeClippedSubviews={true}.

jslok commented Nov 30, 2017

#1831
According to that, the fix was merged in and available for RN 0.50. If you do not want to or cannot upgrade RN yet, you can just change the line as shown in this file.
03ae65b

On my app, this fix solves the issue and I can still use removeClippedSubviews={true}.

@FacuAcosta

This comment has been minimized.

Show comment
Hide comment
@FacuAcosta

FacuAcosta Dec 6, 2017

@douglasjunior Sorry to bother, but how did you implement the Activity Indicator while scrolling the FlatList?

@douglasjunior Sorry to bother, but how did you implement the Activity Indicator while scrolling the FlatList?

@douglasjunior

This comment has been minimized.

Show comment
Hide comment
@douglasjunior

douglasjunior Dec 6, 2017

When fetching the data, render an ActivityIndicator as ListFooterComponent. Example here.

When fetching the data, render an ActivityIndicator as ListFooterComponent. Example here.

@itchingpixels

This comment has been minimized.

Show comment
Hide comment
@itchingpixels

itchingpixels Dec 8, 2017

This is still a problem with 0.50.3. removeClippedSubviews don't seem to have any effect. Can we reopen this please?

This is still a problem with 0.50.3. removeClippedSubviews don't seem to have any effect. Can we reopen this please?

@BlakeSimpson

This comment has been minimized.

Show comment
Hide comment
@BlakeSimpson

BlakeSimpson Dec 11, 2017

Inspired by the comments in this thread from Kiarash-Z and douglasjunior, my fix to this solution was basically:

ListFooterComponent={() => {
  return <View style={{backgroundColor: 'transparent', height: 1}} />
}}

I could not use a ActivityIndicator but it seems RN needs new content to be rendered, even an "invisible" view (Note, with height of zero the bug still existed).

Inspired by the comments in this thread from Kiarash-Z and douglasjunior, my fix to this solution was basically:

ListFooterComponent={() => {
  return <View style={{backgroundColor: 'transparent', height: 1}} />
}}

I could not use a ActivityIndicator but it seems RN needs new content to be rendered, even an "invisible" view (Note, with height of zero the bug still existed).

@companyAcc

This comment has been minimized.

Show comment
Hide comment
@companyAcc

companyAcc Jan 11, 2018

React Native FlatList shows some blank in the quickly sliding. What is the solution?

React Native FlatList shows some blank in the quickly sliding. What is the solution?

@itchingpixels

This comment has been minimized.

Show comment
Hide comment

we've migrated over to use https://github.com/Flipkart/recyclerlistview

@rogerkerse

This comment has been minimized.

Show comment
Hide comment
@rogerkerse

rogerkerse Feb 8, 2018

@BlakeSimpson this is good, but again it is not viable solution in the long run because it is basically a hack.

Why is this closed again, if this is not resolved 👎

@BlakeSimpson this is good, but again it is not viable solution in the long run because it is basically a hack.

Why is this closed again, if this is not resolved 👎

@BlakeSimpson

This comment has been minimized.

Show comment
Hide comment
@BlakeSimpson

BlakeSimpson Feb 8, 2018

@rogerkerse I totally agree. This is a hack and a real solution would be preferable.

We've recently upgraded to RN 0.52 though and the issue seems to be resolved, so I am removing my hack. Perhaps you can upgrade your React Native version also or just use the hack temporarily until you can?

@rogerkerse I totally agree. This is a hack and a real solution would be preferable.

We've recently upgraded to RN 0.52 though and the issue seems to be resolved, so I am removing my hack. Perhaps you can upgrade your React Native version also or just use the hack temporarily until you can?

@Laurensdc

This comment has been minimized.

Show comment
Hide comment
@Laurensdc

Laurensdc Feb 13, 2018

Super weird, when I edited getItemLayout to not match my actual item component, it rendered immediately again for me...

getItemLayout={(data, index) => (
    {
        length: itemWidth - 1, // why does this work
        offset: itemWidth * index,
        index
    }
)}

Edit: Or not.

Laurensdc commented Feb 13, 2018

Super weird, when I edited getItemLayout to not match my actual item component, it rendered immediately again for me...

getItemLayout={(data, index) => (
    {
        length: itemWidth - 1, // why does this work
        offset: itemWidth * index,
        index
    }
)}

Edit: Or not.

@Laurensdc

This comment has been minimized.

Show comment
Hide comment
@Laurensdc

Laurensdc Feb 19, 2018

I might have resolved it by only passing initialScrollIndex if the items would actually go off screen.

initialScrollIndex={sortedEntries.length > 5 ? sortedEntries.length - 1 : 0}

Feels like this kind of logic should not be necessary.

I might have resolved it by only passing initialScrollIndex if the items would actually go off screen.

initialScrollIndex={sortedEntries.length > 5 ? sortedEntries.length - 1 : 0}

Feels like this kind of logic should not be necessary.

@DOHere

This comment has been minimized.

Show comment
Hide comment
@DOHere

DOHere Mar 7, 2018

@bensheldon that solved it for me, thanks!
setting length in getItemLayout to window width worked for me
I had set it before to item length

DOHere commented Mar 7, 2018

@bensheldon that solved it for me, thanks!
setting length in getItemLayout to window width worked for me
I had set it before to item length

@esutton

This comment has been minimized.

Show comment
Hide comment
@esutton

esutton Mar 12, 2018

After refactoring to use FlatList I must go back to ListView. :-(

None of these solutions work for me.

ListView just works.

		"react": "^16.2.0",
		"react-native": "^0.53.3",
		"react-native-router-flux": "4.0.0-beta.27",

esutton commented Mar 12, 2018

After refactoring to use FlatList I must go back to ListView. :-(

None of these solutions work for me.

ListView just works.

		"react": "^16.2.0",
		"react-native": "^0.53.3",
		"react-native-router-flux": "4.0.0-beta.27",
@DOHere

This comment has been minimized.

Show comment
Hide comment
@DOHere

DOHere Mar 12, 2018

@esutton can you show your FlatList, getItemLayout and css used in the FlatList?

DOHere commented Mar 12, 2018

@esutton can you show your FlatList, getItemLayout and css used in the FlatList?

@esutton

This comment has been minimized.

Show comment
Hide comment
@esutton

esutton Mar 12, 2018

@DOHere I am not using the getItemLayout option.

  renderRow = ({ item, index }) => {
    const menuItem = item;
    return (
      <MenuItemRow
        menuItem={menuItem}
        onPressMenuItem={this.onPressMenuItem}
        {...this.props}
      />
    );
  }

  render() {
    const { themeStyle } = this.props.state;
    const connecting = (this.state.animating || this.state.connecting)
      ? (<View style={[styles.row, themeStyle.view]}>
        <Text style={[themeStyle.textPrimary, { fontWeight: 'bold' }]}>
          {this.state.progressMessage}
        </Text>
        <ActivityIndicator
          animating={this.state.animating}
          style={[
            styles.centering,
            {
              backgroundColor: themeStyle.textPrimary.backgroundColor,
            },
          ]}
          color={themeStyle.textPrimary.color}
          size="large"
        />
      </View>)
      : null;

    return (
      <View style={styles.listContainer}>
        {connecting}
        <FlatList
          ref={(ref) => { this.listView = ref; }}
          style={themeStyle.view}
          ItemSeparatorComponent={this.renderSeparator}
          data={this.state.dataSource}
          renderItem={this.renderRow}
          refreshing={this.state.animating}
          onRefresh={this.onTrackerScan}
          automaticallyAdjustContentInsets={false}
          keyboardDismissMode="on-drag"
          keyboardShouldPersistTaps="always"
          enableEmptySections
          keyExtractor={this._keyExtractor}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  centering: {
    alignItems: 'center',
    justifyContent: 'center',
    padding: 8,
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  listContainer: {
    flex: 1,
  },
  list: {
    marginTop: 0,
    backgroundColor: '#eeeeee',
  },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
    padding: 8,
    borderWidth: 0,
    borderColor: '#DDDDDD',
    justifyContent: 'space-between',
  },
  rowSeparator: {
    backgroundColor: 'rgba(0, 0, 0, 0.1)',
    height: 1,
    marginLeft: 4,
  },
  rowSeparatorHide: {
    opacity: 0.0,
  },
  separator: {
    backgroundColor: 'rgba(0, 0, 0, 0.1)',
    height: StyleSheet.hairlineWidth,
    marginVertical: 10,
  },
  separatorHorizontal: {
    backgroundColor: 'rgba(0, 0, 0, 0.1)',
    height: StyleSheet.hairlineWidth,
    marginHorizontal: 10,
  },
});

esutton commented Mar 12, 2018

@DOHere I am not using the getItemLayout option.

  renderRow = ({ item, index }) => {
    const menuItem = item;
    return (
      <MenuItemRow
        menuItem={menuItem}
        onPressMenuItem={this.onPressMenuItem}
        {...this.props}
      />
    );
  }

  render() {
    const { themeStyle } = this.props.state;
    const connecting = (this.state.animating || this.state.connecting)
      ? (<View style={[styles.row, themeStyle.view]}>
        <Text style={[themeStyle.textPrimary, { fontWeight: 'bold' }]}>
          {this.state.progressMessage}
        </Text>
        <ActivityIndicator
          animating={this.state.animating}
          style={[
            styles.centering,
            {
              backgroundColor: themeStyle.textPrimary.backgroundColor,
            },
          ]}
          color={themeStyle.textPrimary.color}
          size="large"
        />
      </View>)
      : null;

    return (
      <View style={styles.listContainer}>
        {connecting}
        <FlatList
          ref={(ref) => { this.listView = ref; }}
          style={themeStyle.view}
          ItemSeparatorComponent={this.renderSeparator}
          data={this.state.dataSource}
          renderItem={this.renderRow}
          refreshing={this.state.animating}
          onRefresh={this.onTrackerScan}
          automaticallyAdjustContentInsets={false}
          keyboardDismissMode="on-drag"
          keyboardShouldPersistTaps="always"
          enableEmptySections
          keyExtractor={this._keyExtractor}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  centering: {
    alignItems: 'center',
    justifyContent: 'center',
    padding: 8,
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  listContainer: {
    flex: 1,
  },
  list: {
    marginTop: 0,
    backgroundColor: '#eeeeee',
  },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
    padding: 8,
    borderWidth: 0,
    borderColor: '#DDDDDD',
    justifyContent: 'space-between',
  },
  rowSeparator: {
    backgroundColor: 'rgba(0, 0, 0, 0.1)',
    height: 1,
    marginLeft: 4,
  },
  rowSeparatorHide: {
    opacity: 0.0,
  },
  separator: {
    backgroundColor: 'rgba(0, 0, 0, 0.1)',
    height: StyleSheet.hairlineWidth,
    marginVertical: 10,
  },
  separatorHorizontal: {
    backgroundColor: 'rgba(0, 0, 0, 0.1)',
    height: StyleSheet.hairlineWidth,
    marginHorizontal: 10,
  },
});

@DOHere

This comment has been minimized.

Show comment
Hide comment
@DOHere

DOHere Mar 12, 2018

@esutton I suggest you set the height of rows somewhere in css
and also use getItemLayout. Try this:

  import { Dimensions } from "react-native";
  screenHeight = Dimensions.get("window").height;

  getItemLayout={(data, index) => ({
          length: screenHeight,
          offset: index * <row-height> + ( <row-height> - screenHeight ) / 2,
          index,
        })}

DOHere commented Mar 12, 2018

@esutton I suggest you set the height of rows somewhere in css
and also use getItemLayout. Try this:

  import { Dimensions } from "react-native";
  screenHeight = Dimensions.get("window").height;

  getItemLayout={(data, index) => ({
          length: screenHeight,
          offset: index * <row-height> + ( <row-height> - screenHeight ) / 2,
          index,
        })}
@esutton

This comment has been minimized.

Show comment
Hide comment
@esutton

esutton Mar 12, 2018

@DOHere Thank you very much for the tip.

I plan to stay with ListView as long as I can. FlatList has wasted way too much of my time.

After my experience of migrating multiple components to FlatList, I have had to roll back to ListView several times because of rendering not working properly as ListView did.

I will keep your advice in mind when I am forced to upgrade to FlatList.

esutton commented Mar 12, 2018

@DOHere Thank you very much for the tip.

I plan to stay with ListView as long as I can. FlatList has wasted way too much of my time.

After my experience of migrating multiple components to FlatList, I have had to roll back to ListView several times because of rendering not working properly as ListView did.

I will keep your advice in mind when I am forced to upgrade to FlatList.

@roshangm1

This comment has been minimized.

Show comment
Hide comment
@roshangm1

roshangm1 Mar 13, 2018

Still with the FlatList in React Native 0.54. It started happening all of a sudden and it's actually annoying.

Still with the FlatList in React Native 0.54. It started happening all of a sudden and it's actually annoying.

@vdlindenmark

This comment has been minimized.

Show comment
Hide comment
@vdlindenmark

vdlindenmark Mar 13, 2018

Please reopen, same issue in RN 0.54 for me... Only Android btw.

vdlindenmark commented Mar 13, 2018

Please reopen, same issue in RN 0.54 for me... Only Android btw.

feelepxyz added a commit to HedvigInsurance/app that referenced this issue Mar 23, 2018

Fix peril icons not always loading in carousel
Related to an issue with Flatlist used in react-native-snap-carousel:
archriss/react-native-snap-carousel#145
facebook/react-native#13316

feelepxyz added a commit to HedvigInsurance/app that referenced this issue Mar 23, 2018

Fix peril icons not always loading in carousel
Related to an issue with Flatlist used in react-native-snap-carousel:
archriss/react-native-snap-carousel#145
facebook/react-native#13316

feelepxyz added a commit to HedvigInsurance/app that referenced this issue Mar 23, 2018

Fix peril icons not always loading in carousel
Related to an issue with Flatlist used in react-native-snap-carousel:
archriss/react-native-snap-carousel#145
facebook/react-native#13316

feelepxyz added a commit to HedvigInsurance/app that referenced this issue Mar 23, 2018

@ArturGr

This comment has been minimized.

Show comment
Hide comment
@ArturGr

ArturGr Apr 25, 2018

Found a working Hack for this.

render() {
       setTimeout(() => {
            this.sectionList && this.sectionList.recordInteraction(); 
        }, 50);
        return (
            <SectionList ref={(view) => { this.sectionList = view }} />
        )
} 

ArturGr commented Apr 25, 2018

Found a working Hack for this.

render() {
       setTimeout(() => {
            this.sectionList && this.sectionList.recordInteraction(); 
        }, 50);
        return (
            <SectionList ref={(view) => { this.sectionList = view }} />
        )
} 
@wmonecke

This comment has been minimized.

Show comment
Hide comment
@wmonecke

wmonecke Apr 28, 2018

I dont encounter this error when I install in debugMode. However once I do react-native run-android --variant=release I get this bug.

In my case the rows do render but kind of "not fully". It feels like because the debug variant is slower, it finishes rendering each item. However the release variant is too fast for the items to display properly. The color of the items are sluggish and blend with the background color.

The bug wont happen on iOS.

I have no clue on what to do to fix this. It is really frustrating.

"react": "16.0.0-alpha.12", "react-native": "0.47.1",

wmonecke commented Apr 28, 2018

I dont encounter this error when I install in debugMode. However once I do react-native run-android --variant=release I get this bug.

In my case the rows do render but kind of "not fully". It feels like because the debug variant is slower, it finishes rendering each item. However the release variant is too fast for the items to display properly. The color of the items are sluggish and blend with the background color.

The bug wont happen on iOS.

I have no clue on what to do to fix this. It is really frustrating.

"react": "16.0.0-alpha.12", "react-native": "0.47.1",

@wenkangzhou

This comment has been minimized.

Show comment
Hide comment
@wenkangzhou

wenkangzhou May 9, 2018

Finally,the only way for me is back to ListView.

Finally,the only way for me is back to ListView.

@pyaesone17

This comment has been minimized.

Show comment
Hide comment
@pyaesone17

pyaesone17 May 16, 2018

<Flatlist style={{ flex: 1 }}/>
This trick work for me without switching to ListView.

pyaesone17 commented May 16, 2018

<Flatlist style={{ flex: 1 }}/>
This trick work for me without switching to ListView.

@wenkangzhou

This comment has been minimized.

Show comment
Hide comment
@wenkangzhou

wenkangzhou May 20, 2018

AddingremoveClippedSubviews = {false}works, but it reducing your rendering performance,if you hava a largelist of image,maybe 500 items can lead to crash.

AddingremoveClippedSubviews = {false}works, but it reducing your rendering performance,if you hava a largelist of image,maybe 500 items can lead to crash.

@machester4

This comment has been minimized.

Show comment
Hide comment
@machester4

machester4 May 22, 2018

had the same problem, the problem is that the data source is a JSON and therefore will be passed to the reference and not as a value, by modifying that object from any of its references automatically 'Flatlist' will have these new data and for more if we use setState to try to update the flatList, we will not see the changes until we move because Flatlist will already have that data. It's a bit confusing but here I give you a little 'solution'.

   // We break the reference by making it immutable 
   let playlistInitial =  JSON.stringify(store.getState().playlist);

    if (playlistInitial != "") {
      this.setState({ playlistInitial });
      AudioController.init(JSON.parse(playlistInitial), 0, this.onChangeStatus);
    }

 <FlatList
     data={this.state.playlist}
     initialNumToRender={5}
     style={{ flex: 1 }}
     horizontal={true}
     showsHorizontalScrollIndicator={false}
     keyExtractor={item => item["key"]}
     renderItem={({ item }) => <RowStationHome data={item} />}
 />

had the same problem, the problem is that the data source is a JSON and therefore will be passed to the reference and not as a value, by modifying that object from any of its references automatically 'Flatlist' will have these new data and for more if we use setState to try to update the flatList, we will not see the changes until we move because Flatlist will already have that data. It's a bit confusing but here I give you a little 'solution'.

   // We break the reference by making it immutable 
   let playlistInitial =  JSON.stringify(store.getState().playlist);

    if (playlistInitial != "") {
      this.setState({ playlistInitial });
      AudioController.init(JSON.parse(playlistInitial), 0, this.onChangeStatus);
    }

 <FlatList
     data={this.state.playlist}
     initialNumToRender={5}
     style={{ flex: 1 }}
     horizontal={true}
     showsHorizontalScrollIndicator={false}
     keyExtractor={item => item["key"]}
     renderItem={({ item }) => <RowStationHome data={item} />}
 />

@facebook facebook locked as resolved and limited conversation to collaborators May 24, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.