web-dev-qa-db-fra.com

Comment améliorer les performances de rendu FlatList pour les grandes listes avec ReactNative 0.43?

J'essaie de rendre une liste d'environ 250 images sur 3 colonnes à l'aide de FlatList dans RN0.43, et je modifie la largeur des images dans la fonction onLayout de FlatList pour l'adapter à la largeur de l'écran.

La performance initiale est correcte, mais après un certain défilement vers le haut ou vers le bas, il faut parfois une seconde ou deux avant que les images ne s'affichent.

c'est encore pire si je change d'orientation, il faut 2 ~ 3 secondes pour que l'écran soit mis à jour.

quelques constatations:

  1. après la rotation de l'écran, il faut une seconde ou deux avant que FlatList.onLayout soit appelé

  2. après FlatList.onLayout et la mise à jour de la largeur de l’image, chaque image (environ la moitié de la liste, environ 150 images, alors que seulement environ 15 sont affichées) est rendue 2 à 4 fois, tandis que render () n’est appelé qu’une fois.

question:

  1. comment puis-je modifier le code pour améliorer les performances?
  2. dans le getItemLayout () d'une liste multicolonne, l'offset devrait-il ressembler à (itemHeight + separatorHeight) * (index% numColumns)?

Merci.

testé sur: GalaxySII (4.1.2) et émulateur Android SDK (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

Déni de responsabilité: Je sais que la question est ancienne, mais voici ma réponse.

Mon application contient beaucoup de listes contenant plus de 500 éléments. Nous sommes donc arrivés à un point où l'application se bloquait sur les téléphones populaires. Ensuite, j’ai fait cette recherche approfondie sur les performances sur FlatLists. } _

La composante FlatList a été présentée comme une alternative à l’ancien ScrollView. Le problème est que ScrollViews rend toute votre liste en même temps, ce qui améliore les performances visuelles, mais il existe un compromis entre la consommation de mémoire, ce qui entraîne le blocage de l'application.

Les listes non hiérarchiques sont donc un mal nécessaire. Ils ne rendent essentiellement que les éléments visibles, ce qui représente un gain considérable en consommation de mémoire, mais une gêne pour les performances visuelles, en particulier pour les éléments lourds/complexes, qui se trouve être votre cas avec ces images sensibles.

Comment contourner ce problème?

Il existe de nombreuses stratégies que vous pouvez mettre en œuvre pour atténuer votre problème.

  • Utilisez des images en cache et performatiques, telles que react-native-fast-image . Chaque opération que vous pouvez supprimer ou abréger pour libérer le fil Javascript: faites-le (chaque image est une new Image(); si elles sont mises en cache, votre hook loaded est appelé plus tôt).

  • Votre composant d'élément de liste est un composant en lecture seule, qui est supposé être «muet». Implémentez une méthode shouldComponentUpdate() { return false } ou une méthode de contrôle de mise à jour plus solide si nécessaire. C'est un coup de pouce énorme.

  • Supprimez console.logs n'importe où près de votre liste. Ils ralentissent vraiment le fil Javascript.

  • Construisez votre application pour la production et testez-la. Cela devient presque toujours deux ou trois fois plus rapide. Dev env est lent à cause du débogage. 

  • Donnez à cet article une bonne lecture pour plus de stratégies.

Conclusion

FlatListEST un composant lent. Ceci est un problème connu, ouvert et bien documenté . Faites ce que vous pouvez pour l’améliorer, et espérons que les versions futures pourront résoudre ce problème.

5
Filipe Merker

Vous recréez de nombreux objets de style pour chaque ligne de la liste individuellement. Cela met beaucoup de trafic sur le pont JS-> Native. Essayez d’utiliser une feuille de style au lieu de transmettre les styles en ligne.

0
vonovak

Oui, je rencontrais le même problème - plusieurs images et vidéos dans la liste réagissaient donc j'ai donc supprimé Flatlist au lieu de cela. J'ai préféré utiliser ListView pour un rendu rapide et pour résoudre le problème de la toucher dans l'élément de liste, mais n'oubliez pas de définir PureComponent sur l'élément de liste 

0
priyanka