React-native: [FlatList] FlatList crashes on device

Created on 21 May 2017  Â·  33Comments  Â·  Source: facebook/react-native

Description

I request server for data 10 items at a time and render those in a FlatList component. Everything is working fine in the emulator but when I build the app in device and scroll up and down very fast the application crashes. I used pure component for each row item of the list and implemented a getItemLayout method but the result is still same.

Example code

import React, { Component } from "react";
import { Text, FlatList, View } from "react-native";
import HistoryRow from './historyRow'
import Loader from '../components/listLoader'
import styles from '../styles/style'

class HistoryList extends Component {
constructor(props) {
super(props)
}

renderSeparator = () => {
    return (
        <View style={{ height: 1, width: "100%", backgroundColor: "#CED0CE", }} />
    );
};

renderFooter = () => {
    if (!this.props.loading) return null;
    return (
        <View style={{ paddingVertical: 20, borderTopWidth: 1, borderColor: "#CED0CE" }} >
            <Loader></Loader>
        </View>
    );
};


render() {

    const { data, refreshCallback, loadMoreCallback, refreshing, loading, historyEnd } = this.props

    if(data.length === 0 && !loading) {
        return (
            <View style={[styles.container, {marginTop: 50}]}>
                <View style={[styles.colCenterCenter]}>
                    <Text>No data found</Text>
                </View>
            </View>
        )
    }

    return (
        <FlatList
            data={data}
            renderItem={({ item }) => (
                <HistoryRow data={item} ></HistoryRow>
            )}

            getItemLayout={(data, index) => {
                return { length: 71, offset: 71 * index, index: index }
            }}

            removeClippedSubviews={false}

            keyExtractor={item => item.transactionId}
            ItemSeparatorComponent={this.renderSeparator}
            ListFooterComponent={this.renderFooter}
            onRefresh={() => { refreshCallback() }}
            refreshing={refreshing}
            onEndReached={() => { loadMoreCallback() }}
            onEndReachedThreshold={.5}
        />
    );
}

}
export default HistoryList;

this is the FlatList component above

//import libraries
import React, { Component } from 'react'
import { View, Text, TouchableHighlight } from 'react-native'
import styles from '../styles/style'

// create a component
export default class HistoryRow extends React.PureComponent {

// pure component implements shouldComponentUpdate by default
constructor(props) {
    super(props)
    this.state = {
        color: 'black'
    }
}

// shouldComponentUpdate(nextProps) {
//  return this.props !== nextProps
// }

colorToggle = (color) => {
    this.setState({color})
}



render() {

    const { data } = this.props

    return (
        <TouchableHighlight
            style={{ paddingVertical: 15, paddingHorizontal: 20, height: 70 }}
            underlayColor="#f47727"
            onPress={() => { }}
            onShowUnderlay={() => { this.colorToggle('white')}}
            onHideUnderlay={() => { this.colorToggle('black')}}
        >
            <View style={[styles.flex1, styles.colSpaceAroundStart]}>
                <View style={[styles.flex1]}>
                    <View style={[styles.flex1, styles.rowCenterCenter]}>
                        <Text style={{color: this.state.color}}>Date: {data.transactionDate}</Text>
                        <Text style={{ marginLeft: 30, color: this.state.color }}>Coin: {data.coinAmount}</Text>
                    </View>
                </View>
                <View style={[styles.flex2]}>
                    <View style={[styles.flex1, styles.colCenterCenter]}>
                        <Text style={{color: this.state.color}}>Description: {data.transactionRemarks}</Text>
                    </View>
                </View>
            </View>
        </TouchableHighlight>
    )
}

}

and here is the row item component.

in the container component inside the componentDid mount i do server request to get the data and I use simple setState when data is received. I am not using redux and I don't think the issue can be related to usage of redux. and after first server call i request for new data inside the onEndReached callback and as the new data comes I merge then with the previous list and call setState again. this is roughly the cycle and it works in emulator even in android device in debug mode. But when I generate a release apk and install it in device not always after some scrolling up and down the application gets crashed.

I am using
classpath 'com.android.tools.build:gradle:1.2.3'
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip
buildToolsVersion "23.0.2"

Stale

Most helpful comment

Ok I found that my issue was not related to FlatList at all, it was two things and both were related to my SVGs. I found this out by profiling the memory usage using Instruments while using the device (iPad) so if anyone is having trouble I'd advise you to see if it's one of your components causing a leak first.

My issue was first of all a memory leak issue with react-native-svg which has since been fixed. My other issue was that making SVGs that are dimensions similar to the device size eat huge amounts of memory (I would have thought as an SVG setting the width/height wouldn't matter as it's an SVG but oh well). I fixed my memory issues by making the SVGs really small and using transform's scale property instead. I hope this helps anyone that had a similar issue. Obviously not saying there aren't edge case crashes which FlatList might have

All 33 comments

My FlatList crashes as well, more so after upgrading to RN 0.44.0

This is a serious bug that should be given high priority. We had observed crashes with large static lists in RN 0.34's ScrollView and ListView. I optimistically upgraded to RN 0.45.1 to use FlatList which is claimed to be more stable. While I haven't yet seen a crash with large static lists of items in FlatList, it has crashed multiple times when dynamically changing the list.

Use case is filtering the items in a FlatList. On initial render all items are shown, then results may be pared down through a search bar.

It did seem to crash when scrolling through the list, but I'm not sure if it was in the process of filtering the results.

It's crashing when rotating the screen. Every 1-3 rotations will consistently crash the app.

@GantMan @superyarik @reneweb @sahrens
Anyone know who maintains FlatList? The crash on rotation is a show stopper.

@ericvicenti Would you be able to help us out?

It's pretty hard to diagnose or even triage the issue without a stack trace of the crash...can you please add one? It's not clear if it's even a native crash or JS exception from your description. Also a repro example would be great, ideally with expo sketch.

Unfortunately I can't capture a stack trace because it's a silent crash. The app quits entirely and there's nothing in the console log. It's much harder to get it to crash in the debugger, yet is very reproducible in a production build. Try rotating the device a few times with a populated FlatList.

There should be someway to get the output. This may help:

https://stackoverflow.com/questions/35364373/android-app-crashes-without-any-logcat-or-any-exception

At the very least please include the full logcat output in a gist or something.

Thanks that's helpful. Is there an equivalent for iOS / Xcode?

Another google search reveals this: https://stackoverflow.com/questions/36788837/ios-app-crashes-but-there-is-no-crash-log-available

How are you running and installing your production build? Are you using expo? If not, what native modules are you using? The more details you provide, the more likely we can help.

Note that this is probably not a FlatList issue - JS code should not be able to crash the device without a JS stack trace. It's probably a bug with the bridge, layout, some native module or native glue code, and your list is probably tickling the bug somehow.

I've still not been able to capture any information in the debugger. One production crash report pointed to Layout Animation which is used in the FlatList rows. Not definitive whether that's the culprit. Will continue investigating.

It's incredibly difficult (impossible?) to recreate In the debugger. I've held down the rotation keys so that it rotates many times per second, hundreds of times continuously, and it won't crash. In production on a real device it silently crashes every 2-10 rotations.

Edit: The chance of crashes increases as the number & complexity of rows increases. For a relatively small number of rows (~5) it won't crash. At ~50 rows it crashes fairly often on rotation. Each row contains an accordion (can be expanded or minimized) containing a responsive child component that automatically resizes based on width.

Edit2: Not using Expo. Using Redux, react-native-animatable, react-native-device-info, react-native-newrelic, and a slew of other modules. Not all have native pieces or aren't in the FlatList rows.

Same issue but on old device particularly. I noticed that on android over 4 years. I'm using redux too. Without Redux, crashes are less frequent..

In case this benefits anyone, won't apply to all... check for seemingly non-related culprits. As @sahrens pointed out, problem likely isn't a FlatList issue. In my case I found a custom svg icon in my renderItem component was causing the crash on device when it hadn't elsewhere—replaced it with a react-native-vector-icon and everything functions as it should.

I'm using Redux as well. I'm not convinced this isn't a Flatlist bug. Definitely a corner case that's very hard to reproduce in the debugger. The reasons I believe it's Flatlist:

  • The exception happens in native code. No JS stacktrace.
  • No crashes when the list is small (~10) even with complex rows.
  • Crashes as the number of rows and complexity increases. Empirically this has been around 50+ rows.

My hunch is that it's related to FlatList dynamically culling the off-screen rows from memory and adding new ones as they come into view. Many of the NewRelic crash reports end with libobjc.A.dylib | objc_object::release

I'm using mobx and my list crashes when the app navigates to a new screen after the user clicked on one of the rows. When there is a small amount of rows everything works perfect!
Any update on this?

Does it work after removing ItemSeparatorComponent? Im facing this recently

Our app doesn't use ItemSeparatorComponent in FlatList.

I have reduced the crash frequency by a small amount by minimizing state updates. Standard React optimization strategies using shouldComponentUpdate, componentWillReceiveProps, etc. Hopefully that gives a clue to the underlying cause.

Best way is to never update state in the flatlist. Only update props with
extraData on props who shouldUpdate and your flatlist will never crash.
This is a pure component, that’s why :)
Le ven. 8 déc. 2017 à 10:40, Peace notifications@github.com a écrit :

Our app doesn't use ItemSeparatorComponent in FlatList.

I have reduced the crash frequency by a small amount by minimizing state
updates. Standard React optimization strategies using
shouldComponentUpdate, componentWillReceiveProps, etc. Hopefully that gives
a clue to the underlying cause.

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/facebook/react-native/issues/14086#issuecomment-350218768,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AJx0It-N9vEm1W_PEMG4XlSA6H7_sbHzks5s-QQUgaJpZM4NhnL8
.

@peacechen Do I need pure component even if my flat list does not change. By state updates are you talking about overall state updates or state updates for the dataSource used in flatlist?

Thanks @MalguyMQ , I'll look into how state updates are happening.

@pavanmehta91 yes I believe state updates are being passed to dataSource.

I've updated it so that the data prop passed to FlatList never changes. The renderItem method applies the filter.
This unfortunately doesn't work in another place where numColumns = 2. renderItem applies the filter and returns undefined for items that are filtered out, but FlatList places an undesired blank space there.

@MalguyMQ How does one implement infinite scroll if FlatLists's data props is never mutated? This guy freely mutates state passed to data prop:
https://www.youtube.com/watch?v=rY0braBBlgw

@peacechen, the best way to filter your data is to call a function who filter data in your props and dispatch new data filtered. If you are using redux. If you don’t use redux as external state you need to use your state inside your component. You can did it in your state if you like in the video. But don’t forget in the video it’s just an exemple, not ready for production.

Last advice, when your props is updated, if your extraData is like: extraData={this.props} and your dataSource={this.props.myData} your render items function will be called for each new items.

Can you share your code if your not able to achieve this. It’s gonna be more easy to help you ;)

Hi, I'm having the same issue. App crashes after pressing a Flatlist element with onPress prop.
I only have this issue when remote JS debbuging is off. When its on, everything works fine.
I have TouchableOpacity as Parent in all my rows in Flatlist. It crashes only when TouchableOpacity has onPress prop with a function other then () => {}. When I dont provide an onPress prop or set it to () => {}, it doesnt crash at all.

Tried with TouchableWithoutFeedback and others too, same result.

FlatList is crashing for me only if I set horizonta={true}, it never crashes without it.

I've just run into the same issue when I upgraded from ListView to FlatList. I have an infinite scroll which loads 10 items at a time. First page is fine and then after the second page loads it works for a second and then silently crashes.

All I can see in the logs is an "out of memory error", no other logs indicating the root cause. I only got a little time yesterday to look into it so will spend some time time tonight trying to diagnose. If I find my problem I'll update (or if it's unrelated to FlatList I'll delete this comment).

Also, I should point out that adding removeClippedSubviews improved it a little, I could load a few pages but after a while I managed to crash it again. Obviously this isn't a solution as this property really messes up my rendering in some cases. Just wanted to point it out.

Edit: I did some more testing for my case. I have very complex items which contain a few SVG elements. When I stripped out all of these to bring it down to the bare bones I had no issues. I also realised I had some unnecessary re-renders even though I had pure components. I tweaked this to use shouldComponentUpdate but I still get the errors with the SVG elements included so still investigating

Might not help others but, my FlatList caused silent crashes when I was calling:

componentWillUnmount() {
    RNFetchBlob.fs.unlink(this.state.path);
  }

for every FlatList element. When swipe to go back was initiated, it would cause the crash on the large list ~30 items.

Both my scrollview with netsted flatlists and regular scrollview crashes on Android devices only.

For me, the problem was passing large objects when navigating. When I changed it to strings and saved everything in a service, everything worked fine.

My problem gotten resolved I did 2 things
1) Move my FlatList outside from the ScrollView (Note: It only crashed in android and not in IOS)
2) I resized my images before storing them in s3.

@pavanmehta91 Having same issue on Android real devices only, but how did you manage to keep same behavior without the scrollview parent?

Ok I found that my issue was not related to FlatList at all, it was two things and both were related to my SVGs. I found this out by profiling the memory usage using Instruments while using the device (iPad) so if anyone is having trouble I'd advise you to see if it's one of your components causing a leak first.

My issue was first of all a memory leak issue with react-native-svg which has since been fixed. My other issue was that making SVGs that are dimensions similar to the device size eat huge amounts of memory (I would have thought as an SVG setting the width/height wouldn't matter as it's an SVG but oh well). I fixed my memory issues by making the SVGs really small and using transform's scale property instead. I hope this helps anyone that had a similar issue. Obviously not saying there aren't edge case crashes which FlatList might have

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as "For Discussion" or "Good first issue" and I will leave it open. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings