web-dev-qa-db-fra.com

Utiliser requestAnimationFrame dans React

Je suis nouveau pour réagir en natif et j'essaie d'optimiser les performances. 

Les événements My Touch sont très lents et je parcourais la documentation RN sur les performances et ils ont mentionné l'utilisation de requestAnimationFrame avec cet exemple

handleOnPress() {
  // Always use TimerMixin with requestAnimationFrame, setTimeout and
  // setInterval
  this.requestAnimationFrame(() => {
    this.doExpensiveAction();
  });
}

Maintenant, cette description semble très vague et difficile pour moi de comprendre son utilisation 

Comme, j'ai cet événement palpable dans mon application RN

<TouchableWithoutFeedback   onPress={() => this.touched(this.props.coinShortName)}>

Qui appelle cette méthode 

 touched = (id) => {

        this.setState({selectedPostId: id})
        if (this.props.coinShortName == this.state.selectedPostId ) { 
           this.setState({stateToDisplay: !this.state.stateToDisplay})
        }
    }

[Question:] Quelqu'un peut-il me dire comment je dois/dois l'utiliser dans mon application?

5
iRohitBhatia

Je vais convertir mon commentaire en réponse afin que je puisse mieux le formuler et, espérons-le, aider quelqu'un à l'avenir également. Je ne recommande pas expressément de marquer ma réponse comme étant correcte, mais je pense que cette réponse devrait figurer ici à côté de cette question.

Cet article devrait vous donner un aperçu de requestAnimationFrame: http://www.javascriptkit.com/javatutors/requestanimationframe.shtml .

Je recommanderais de lire l'article que j'ai lié ci-dessus et de lire ensuite ma réponse.

Je vais simplement mentionner explicitement que requestAnimationFrame pourrait ressembler à setTimeout(() => {}, 0), mais si vous aviez un téléphone Zack Morris fabriqué en 1985, son "dès que possible" pourrait prendre 5 secondes plus tard, ce qui donnerait à votre animation une apparence terrible, semblable à celle de votre personnage. traîne à travers l'écran dans un jeu vidéo. La fonction a peut-être été appelée au bon moment, mais elle ne s’est pas exécutée au bon moment.

Il peut être utile d’imaginer une phase de collecte et une phase de rendu. Je suis désolé, je ne connais pas les termes exacts pour ce genre de choses, mais les yeux humains voient un mouvement en douceur à 20 FPS, mais cela signifie que vous avez 20 "images", ce qui revient à calculer 20 fois. C'est comme ramasser un groupe d'enfants et les pousser dans un bus 20 fois par seconde. Les pousser dans le bus est un événement, et cela revient à repeindre votre écran. Parfois, les enfants peuvent être laissés pour compte et des enfants supplémentaires ramassés la prochaine fois, de sorte que vous pouvez imaginer les avantages de la fluidité perçue avec le temps.

Il est important de noter que des optimisations sont en cours en ce qui concerne la prochaine peinture ou la prochaine fois que l'écran «change». requestAnimationFrame fonctionne sous le capot pour s'assurer que l'animation se déroule au bon moment et qu'elle est fluide, ce qui signifie que les pixels étaient là où ils étaient censés se trouver au bon moment. (Je pense que vous obtiendriez beaucoup de sens si vous vérifiiez les définitions de "qu'est-ce qu'une animation", et regardez-vous dans la discussion à ce sujet. Je le mentionne parce que nous voulons en savoir plus sur le processus de repeinte et ce les choses sont importantes et pourquoi)

Je me souviens que requestAnimationFrame peut abandonner les calculs qui arriveraient trop tard. Par exemple, si vous cliquez sur le bouton et qu'un pixel passe de 0% à 25% à 50% à 75% à 100% (calcul de distance arbitraire). Nous pourrions dire qu'après 1 seconde, le pixel devrait avoir parcouru 50% de la distance et après 2 secondes, il devrait être à 100%, le dernier lieu de repos.

Il est plus important que les pixels soient au bon endroit et au bon moment que pour eux de se rendre exactement à l'endroit où ils étaient censés se rendre. requestAnimationFrame vous aide à le faire. Si l'écran est sur le point de repeindre et qu'il "doit" exécuter un calcul trop long, "il" l'ignore et passe à l'image suivante. C'est comme couper du gras pour garder le rythme et éviter les jank.

requestAnimationFrame est une solution aux mêmes problèmes, que ce soit dans votre navigateur Web, iOS ou Android. Ils font tous ce processus de peindre l'écran encore et encore. Vous pouvez commencer à calculer quelque chose de nécessaire pour le prochain repeindre mais commencer trop tard pour ne pas le faire lors du prochain repeint.

Imaginez que votre animation soit fluide mais que votre téléphone reçoive tout de suite 20 notifications Push qui bloquent le processeur, ce qui retarde votre animation de 16.7 milliseconds. Plutôt que d'afficher le pixel au bon endroit au mauvais moment, requestAnimationFrame aide à placer le pixel à la bonne place au bon moment, mais cela peut faire de la magie et même ne pas essayer de peindre le pixel parfois alors qu'il aurait autrement. , permettant ainsi d’économiser les performances et d’augmenter la douceur perçue.

Je viens de me rendre compte qu'il s'agit d'un mur de texte, mais je pense que ce sera informatif.

Ces repeints se produisent environ 60 images par seconde, donc requestAnimationFrame pourrait se déclencher environ 60 fois par seconde lorsqu'il calcule que le temps est optimal. Il y a 1000 millisecondes en 1 seconde, donc 60 images par seconde est une image par 16.7ms. Si l'œil humain perçoit un lissage à 20 images par seconde, cela signifie que vous pouvez en principe repeindre toutes les 45 ms ou 30% autant et que l'animation reste fluide.

Mes définitions peuvent être inexactes, mais j'espère qu'elles pourront vous aider à vous donner une idée de ce qui se passe.

3
agm1984

Comme mentionné, vous devez envelopper votre action coûteuse dans une instance de requestAnimationFrame.

Usage

<TouchableWithoutFeedback onPress={() => this.touched(this.props.coinShortName)}>

touched = (id) => {
  requestAnimationFrame(() => {
    this.setState({selectedPostId: id})
    if (this.props.coinShortName == this.state.selectedPostId ) {
     this.setState({stateToDisplay: !this.state.stateToDisplay})
    }
  });
}
0
Pritish Vaidya
<TouchableWithoutFeedback onPress={this.handlePress}>

handlePress = () => {
   this.requestAnimationFrame(() => {
     this.touched(this.props.coinShortName)
   });
}

il serait préférable que vous supprimiez le paramètre id inutile dans la fonction touched en utilisant directement this.props.coinShortName dedans pour pouvoir écrire

handlePress = () => {
   this.requestAnimationFrame(this.touched);
} 

Quoi qu'il en soit, la fonction touched ne semble pas vraiment chère, donc je ne sais pas si cela résoudra votre problème de performances.

0
Olivier Boissé