wake-up-neo.com

Wie verbessert man die FlatList-Renderleistung für große Listen mit ReactNative 0.43?

Ich versuche mit FlatList in RN0.43 eine Liste von ~ 250 Bildern in 3 Spalten zu rendern und ändere die Breite der Bilder in der OnLayout-Funktion der FlatList, um sie an die Breite des Bildschirms anzupassen.

Die anfängliche Leistung ist in Ordnung, aber nach einigem Scrollen nach oben/unten dauert es manchmal eine oder zwei Sekunden, bis die Bilder angezeigt werden.

es ist noch schlimmer, wenn ich zur Bildschirmausrichtung wechsle. Es dauert 2 bis 3 Sekunden, bis der Bildschirm aktualisiert ist.

ein paar erkenntnisse:

  1. nach dem Drehen des Bildschirms dauert es eine oder zwei Sekunden, bis FlatList.onLayout aufgerufen wird

  2. nach FlatList.onLayout und Aktualisierung der Bildbreite wird jedes Bild (ungefähr die Hälfte der Liste, ~ 150 Bilder; es werden nur ~ 15 angezeigt) zwei- bis viermal gerendert, während render () nur einmal aufgerufen wird.

frage:

  1. wie kann ich den Code ändern, um die Leistung zu verbessern?
  2. sollte der Versatz im getItemLayout () einer mehrspaltigen Liste so etwas wie (itemHeight + separatorHeight) * (index% numColumns) sein?

Vielen Dank.

getestet auf: GalaxySII (4.1.2) und Android SDK Emulator (7.1.1)

var data = [
    require('./res/img/Search.png'),
    require('./res/img/test - Copy.png'),
    // ~250 items
    ...];

class app extends React.Component {
    renderItem (info, width) {
        console.log('renderItem', info.index);
        if(width !== this.width) {
            this.imageStyle = {width: width-MarginHorizontal , height: width-MarginHorizontal, resizeMode: 'contain'};
        }
        return (
            <Image
                source = {info.item}
                key = {info.index}
                style={this.imageStyle}/>
            );
    }

    render() {
        console.log('Test.render');
        return (
            <View style={{
                flex: 1,
                flexDirection: 'row',
                justifyContent: 'flex-start',
                alignItems: 'center',
                backgroundColor: '#F5FCFF'
            }}>
                <GridList
                    numColumns={3}
                    columnWrapperStyle={{ alignItems: 'center', marginVertical: 5, justifyContent: 'space-around'}}
                    data={data}
                    renderItem={this.renderItem}
                />
            </View>
        );
    }
}

class GridList extends Component {
    onLayout(event) {
        console.log('GridList.onLayout()');
        let newColumnWidth = event.nativeEvent.layout.width/ this.numColumns;
        this.layout = Object.assign({},event.nativeEvent.layout);
        if( undefined === this.columnWidth  || Math.abs(newColumnWidth - this.columnWidth) > WidthTolerance ) {
            this.columnWidth = newColumnWidth;
            if(this.isComponentMounted) {
                this.setState({renderCount: this.state.renderCount+1});
            } else {
                this.state.renderCount +=1;
            }
        }
    }
    render() {
        console.log('GridList.render()');
        return (
            <FlatList
                {...(this.modifiedProps)}
                renderItem={(info) => { return this.props.renderItem(info, this.columnWidth); }}>
                {this.props.children}
            </FlatList>
        );
    }
}
16
John Ng

Disclaimer: Ich weiß, dass die Frage alt ist, aber hier ist meine Antwort.

Meine App verfügt über eine Liste von Listen mit mehr als 500 Elementen. So kamen wir an einen Punkt, an dem die App auf gängigen, nicht bösen Handys abstürzte. Dann habe ich diese umfangreiche Recherche über die Leistung bei FlatLists) durchgeführt.

Die FlatList-Komponente wurde als Alternative für die alte ScrollView vorgestellt. Das Problem ist, dass ScrollViews alle Ihre Liste gleichzeitig rendert, um eine bessere visuelle Leistung zu erzielen. Es gibt jedoch einen Kompromiss beim Speicherbedarf, der zu App-Abstürzen führt.

Flache Listen sind also ein notwendiges Übel. Sie rendern im Wesentlichen nur sichtbare Elemente. Dies ist ein enormer Gewinn für den Speicherverbrauch, jedoch ein Nachteil für die visuelle Leistung, insbesondere bei schweren/komplexen Objekten. Dies ist der Fall bei reaktionsfähigen Bildern.

Wie umgehen?

Es gibt viele Strategien, die Sie implementieren können, um Ihr Problem zu mildern.

  • Verwenden Sie zwischengespeicherte und performatische Bilder, z. B. reag-native-fast-image . Jede Operation, die Sie entfernen oder abkürzen können, um den Javascript-Thread freizugeben: do it (jedes Bild ist eine new Image(). Wenn sie zwischengespeichert werden, haben Sie Ihren loaded-Hook früher aufgerufen.)

  • Ihre Listenelementkomponente ist eine schreibgeschützte Komponente, die "dumm" sein soll. Implementieren Sie nach Bedarf eine shouldComponentUpdate() { return false }- oder eine solidere Update-Kontrollmethode. Dies ist ein RIESIGER Perfomance-Boost.

  • Entfernen Sie console.logs in Ihrer Nähe. Sie verlangsamen den Javascript-Thread wirklich schlecht.

  • Bauen Sie Ihre App für die Produktion auf und testen Sie sie. Es wird fast immer zwei- bis dreimal schneller. Dev Env ist wegen Debugging langsam. 

  • Geben Sie diesem Artikel eine gute Lektüre für weitere Strategien.

Fazit

FlatListISTeine langsame Komponente. Dies ist eine bekannte, offene und gut dokumentierte Ausgabe . Tun Sie, was Sie können, um es zu verbessern, und hoffen wir, dass zukünftige Versionen dies beheben werden.

5
Filipe Merker

Sie erstellen viele Stilobjekte für jede Zeile der Liste einzeln neu. Dies bringt viel Verkehr auf die JS-> Native Bridge. Verwenden Sie Stylesheet, anstatt die Styles inline zu übergeben.

0
vonovak

Ja, ich hatte das gleiche Problem - mehrere Bilder und Videos in der Liste reagierten nativ. Deshalb entfernte ich stattdessen Flatlist. Ich zog es vor, ListView zu verwenden, um schnell zu rendern und das Berührbarkeitsproblem für Listenelemente zu beheben. Vergessen Sie jedoch nicht, PureComponent auf das Listenelement zu setzen 

0
priyanka