
React-nativ-Best-Practice ist ein reagierender Best Practice und ein Paket, das Techniken zur Erhöhung der Leistung sowie für Versorgungsunternehmen zur Erhöhung der Leistung der App bietet
Sie sollten WARE-DID-you-Render verwenden, die Sie über potenziell vermeidbare Wiederverbesserer informieren.
import React from 'react' ;
const useWDYR = __DEV__ ;
if ( useWDYR ) {
const whyDidYouRender = require ( '@welldone-software/why-did-you-render' ) ;
whyDidYouRender ( React , {
// Enable tracking in all pure components by default
trackAllPureComponents : true ,
trackHooks : true ,
include : [
// Uncomment to enable tracking in all components. Must also uncomment /^Screen/ in exclude.
// /.*/,
// Uncomment to enable tracking by displayName, e.g.:
// /^Components/,
] ,
exclude : [
// Uncomment to enable tracking in all components
// /^Components/,
] ,
} ) ;
} Importieren Sie den obigen Dateicode in Ihren App Root index.js
Sie können eine Komponente überspringen, wenn ihre Requisiten unverändert sind.
Es ist wichtig, schwere Berechnungen sowie Arrays und Objektkreationen zu merken, damit sie bei jedem Render nicht neu erstellt werden. Ein Neurender tritt auf, wenn sich Status ändert, redux einige Aktionen sendet oder wenn der Benutzer in eine Texteingabe eingeht (für jeden einzelnen Tastendruck neu render). Sie möchten aus sehr offensichtlichen Gründen nicht viele Operationen in diesen Rendern ausführen - also ohne schwere Filterung, keine Listenvorgänge usw.
Eine reine Komponente (oder eine React.memo Komponente) wird nicht erneut gerendert, wenn die Requisiten flach gleich sind.
Jede Variable, die Sie in Ihrer Renderfunktion erstellen, wird bei jedem Render erneut zugeteilt. Dies ist zwar kein Problem für Werttypen , aber dies führt dazu, dass Referenztypen bei jedem Render unterschiedlich sein. Wenn Sie diese Variablen über Requisiten an reine Komponenten weitergeben, werden sie immer noch erneut rendern, obwohl die Requisiten logischerweise gleich sind. Oft gehen diese Variablen sogar über die Brücke und machen Ihre App langsamer.
Wenn sich eine reine Komponente erneut angeregt hat, vergleicht er die vorherigen Requisiten mit den aktuellen Requisiten und Überprüfungen, ob sie flach gleich sind.
Zahlen , Zeichenfolgen und Booleschen sind Werttypen , was bedeutet, dass sie nach Wert verglichen werden können:
const i1 = 7 ;
const i2 = 7 ;
const equal = i1 === i2 ; // trueObjekte , Arrays und Funktionen sind Referenztypen , was bedeutet, dass sie nicht durch ihren logischen Wert verglichen werden können, sondern mit Referenz verglichen werden müssen:
const o1 = { x : 7 } ;
const o2 = { x : 7 } ;
const equal = o1 === o2 ; // false Referenzvergleiche vergleichen einfach die Speicheradresse der Variablen, sodass nur o1 === o1 im obigen Codebeispiel der true wäre.
'tequal
fromreagieren nativ-best-practice', um Objekte mit der tatsächlichen Gleichheit zu vergleichen, aber das ist keine flache Gleichheit mehr.
Wenn Sie Objekte in Ihrer Renderfunktion erstellen, werden sie bei jedem einzelnen Rendern neu erstellt. Dies bedeutet, dass wenn Sie im ersten Render ein Objekt erstellen, es nicht auf das Objekt im zweiten Render referenziert . Aus diesem Grund gibt es eine Memoisierung.
useMemo Haken, um Arrays und Objekte zu meimen, die ihre Referenzgleichheit beibehalten (und bei jedem Rendern nicht neu erstellt werden), solange die Abhängigkeiten (zweites Argument) gleich bleiben. Verwenden Sie auch useMemo , um schwere Berechnungen wie Array -Operationen, Filterung usw. zu zwischenstrahlen.useCallback -Hook, um eine Funktion zu meimen.useDeepEffect , useDeepCallback , useDeepImperativeHandle und useDeepLayoutEffect aus import {useDeepEffect, ...} from 'react-native-best-practice' verwenden.Im Allgemeinen können Funktionskomponenten aufgrund des Konzepts von Haken einfacher optimiert werden. Sie können jedoch ähnliche Techniken für Klassenkomponenten anwenden. Beachten Sie einfach, dass dies zu viel mehr Code führt.
Während Animationen und leistungsintensive Aufgaben auf nativen Threads geplant sind, läuft Ihre gesamte Geschäftslogik auf einem einzelnen JavaScript -Thread. Stellen Sie daher sicher, dass Sie dort so wenig Arbeit wie möglich erledigen. Zu viel Arbeit am JavaScript -Thread kann mit einem hohen Ping in einem Videospiel verglichen werden - Sie können sich immer noch reibungslos umsehen, aber Sie können das Spiel nicht wirklich spielen, weil jede Interaktion zu lange dauert.
Native Komponenten ( <View> , <Text> , <Image> , <Blurhash> , ...) müssen Requisiten über die Brücke an native weitergeben. Sie können memoisiert werden, daher vergleicht React die Requisiten für flache Gleichheit und übergeht sie nur über die Brücke, wenn sie sich von den Requisiten des letzten Renders unterscheiden. Wenn Sie sich nicht richtig merken, können Sie für jeden einzelnen Rendern Requisiten über die Brücke weitergeben, sodass die Brücke sehr besetzt ist. Sehen Sie sich das Beispiel für Stile an - Stile werden bei jedem erneuten Render über die Brücke geschickt!
Hier sind einige Beispiele, mit denen Sie nicht zu viel Arbeit an Ihrem JavaScript -Thread erledigen können:
return < View style = { [ styles . container , { backgroundColor : 'red' } ] } /> ; const style = useMemo ( ( ) => [ styles . container , { backgroundColor : 'red' } ] , [ ] ) ;
return < View style = { style } /> ;useAnimatedStyle , wie diese dynamisch sein müssen. Durch die Verwendung filter , map oder anderen Array -Operationen in Renderern werden die gesamten Operation für jeden Render erneut ausgeführt.
return (
< Text > { users . filter ( ( u ) => u . status === 'online' ) . length } users online </ Text >
) ; const onlineCount = useMemo (
( ) => users . filter ( ( u ) => u . status === 'online' ) . length ,
[ users ]
) ;
return < Text > { onlineCount } users online </ Text > ; Sie können dies auch anwenden, um mehrere React -Ansichten mit .map zu machen. Diese können auch mit useMemo ausgeliefert werden.
return < View onLayout = { ( layout ) => console . log ( layout ) } /> ; const onLayout = useCallback ( ( layout ) => {
console . log ( layout ) ;
} , [ ] ) ;
return < View onLayout = { onLayout } /> ; Stellen Sie sicher, dass Sie auch über andere Anrufe im Renderer, z. B. useSelector , useComponentDidAppear nachdenken - wickeln Sie den Rückruf auch dort ein!
function MyComponent ( props ) {
return < PressableOpacity onPress = { ( ) => props . logoutUser ( ) } /> ;
} function MyComponent ( props ) {
return < PressableOpacity onPress = { props . logoutUser } /> ;
} function MyComponent ( props ) {
return (
< RecyclerListView scrollViewProps = { { horizontal : props . isHorizontal } } />
) ;
} function MyComponent ( props ) {
const scrollViewProps = useMemo (
( ) => ( {
horizontal : props . isHorizontal ,
} ) ,
[ props . isHorizontal ]
) ;
return < RecyclerListView scrollViewProps = { scrollViewProps } /> ;
} function MyComponent ( ) {
return < RecyclerListView scrollViewProps = { { horizontal : true } } /> ;
} const SCROLL_VIEW_PROPS = { horizontal : true } ;
function MyComponent ( ) {
return < RecyclerListView scrollViewProps = { SCROLL_VIEW_PROPS } /> ;
} Dies gilt sowohl für Objekte als auch für Funktionen, die nicht vom Zustand oder den Requisiten der Komponente abhängen. Verwenden Sie dies immer, wenn Sie können, da es noch effizienter ist als useMemo und useCallback .
const [ me , setMe ] = useState ( users . find ( ( u ) => u . id === myUserId ) ) ; const [ me , setMe ] = useState ( ( ) => users . find ( ( u ) => u . id === myUserId ) ) ; Der useState -Hook akzeptiert eine Initialisiererfunktion. Während das erste Beispiel ("schlecht") die .find bei jedem Rendern ausführt, führt das zweite Beispiel nur einmal die übergebene Funktion aus, um den Status zu initialisieren.
Beim Schreiben neuer Komponenten habe ich immer eine Protokollanweisung in meine Renderfunktion eingelegt, um passiv zu beobachten, wie oft meine Komponenten-Wiederverlängerung während der Arbeit daran arbeiten. Im Allgemeinen sollten Komponenten so wenig wie möglich wieder auftreten, und wenn ich viele Protokolle in meiner Konsole sehe, weiß ich, dass ich etwas falsch gemacht habe. Es ist eine gute Paktierung, diese Funktion in Ihre Komponente zu setzen, sobald Sie damit anfangen, daran zu arbeiten, und sie nach dem Abschluss zu entfernen.
function ComponentImWorkingOn ( ) {
// code
console . log ( 're-rendering ComponentImWorkingOn!' ) ;
return < View /> ;
}Sie können auch die Why-You-Render-Bibliothek verwenden, um herauszufinden, warum eine Komponente erneut gerendert hat (Prop-Änderungen, Zustandsänderungen, ...) und möglicherweise frühzeitig Fehler aufnehmen.
React.memo export const MyComponent = ( props ) => {
return ...
} const MyComponentImpl = ( props ) => {
return ...
}
export const MyComponent = React . memo ( MyComponentImpl ) ; Wenn Ihre Komponente das gleiche Ergebnis mit den gleichen Requisiten erzielt, können Sie es in einen Aufruf einwickeln, um zu React.memo(...) . Dies bedeutet, dass React übersprungen wird, um die Komponente zu rendern und das zuletzt erzielte Ergebnis wiederzuverwenden. Siehe die offiziellen Dokumente für React.memo und verwenden Sie React.memo(...) mit Bedacht.
Wenn sich Ihre App langsam anfühlt, probieren Sie die React-Native-Performance-Bibliothek und das Flipper-Plugin, um die Leistung Ihrer App in verschiedenen Aspekten wie Zeit bis interaktiv , Komponenten-Renderzeit , Skriptausführung und mehr zu profilieren.
Nicht vorzeitig optimieren. Einige hier verwendete Beispiele (z. B. der useMemo ) sind sehr klein und zeigen nur die Idee. Ein Haken wie "Usememo" hat auch Kosten (die Funktion und das DEPS -Array, das Aufrufen des tatsächlichen Hakens und das Ausführen eines Array -Vergleichs). Denken Sie also daran, dass es oft besser ist, Objekte oder Arrays direkt zu übergeben, wenn die Komponente selbst optimiert ist. Nach einer bestimmten Komponentenkomplexität oder einem bestimmten Abhängigkeitsgraphen können Memoisierungsfunktionen ein großer Leistungsgewinn sein, aber es gibt auch Fälle, in denen es nur zu unnötig komplexen Code und manchmal noch schlechteren Leistung führt. Immer vor und nachher ein Benchmark!
npm i react-native-best-practice
Alle bestehenden Argumente wie in nativen React Hooks mögen
import {useDeepEffect} from 'react-native-best-practice'
useDeepEffect(()=>{
},[recreatedDeepObject])
useDeepEffect => useEffectuseDeepMemo => useMemouseDeepCallback => useCallbackuseDeepImperativeHandle => useImperativeHandleuseDeepLayoutEffect => useLayoutEffectisEqual => prüft isequal tiefgreifendcloneDeep => klonen Objekt und Array tief Schalten Sie immer die Pref -Monitor ein, während Sie die App entwickeln, da Sie die UI -Framerate und die JS -Framerate Show Perf Monitor . Wenn ein Frame -Fall abfällt, können Sie überprüfen, welcher neue Code dazu führt, dass der Frame abgelegt wird, und Sie haben Ihre Dev Menu für interaktives (TTI) Tief. 
Verwenden Sie niemals die Flatliste, verwenden Sie immer Flashlist, da das Konzept der Recyclingansichten verwendet wird, die nur eine begrenzte Anzahl von Ansichten erstellen und auf dem Bildschirm sichtbar sind
Erstellen Sie eine benutzerdefinierte Logger -Instanz und erzwingen Sie Emojis, um Protokolle zu kategorisieren. Auf diese Weise ist es einfacher, relevante Linien in Ihrer Konsole zu erkennen und sieht insgesamt freundlicher aus. Machen Sie viel Protokollierung, um sich zu einem späteren Punkt vor langen Nächten des Debuggens zu retten! 
Verwenden Sie immer den nativen Stapel von @reactnavigation. Da es Plattform-native Bildschirmprimitive verwendet, ist es fast immer die Leistungsgewinne gegenüber dem JS-basierten Stack wert. 
Redux Wenn Sie bereits Redux verwenden, sollten Sie die Memoized -Funktionen für den Memoized verwenden
React-Kontext Wenn Sie bereits den React-Kontext verwenden, sollten Sie den Verwendungskontext-Selektor für memoisierte "Selektor" -Funktionen verwenden, da sonst ein Kontextwert geändert wird. Alle Komponenten, die Usecontext erneut rendern.
Empfohlen, diese LIBS -Rückstoß zu verwenden, Jotai Zustand für staatliches Management
Wenn Sie etwas in untergeordneten Komponenten aus der übergeordneten Komponente tun müssen, verwenden Sie Ref und UsesimperativeHandle zum Aufrufen von Funktionen von untergeordneten Komponenten aus der übergeordneten Komponente, anstatt mit staatlicher State zu spielen, die in Kinderkomponenten übergehen
Verwenden Sie die React-Native-Buffer-Gabel von @craftZdog, wenn Sie sich mit vielen Puffern befassen, um Ihre App zu beschleunigen. Es verwendet C ++ Backed Implementierungen, die über JSI exponiert sind, was ungefähr 4x schneller ist als die JS-basierte Implementierung. 
Verwenden Sie React-Native-MMKV, um Daten synchron zu speichern und aus lokalem Speicher abzurufen, die auch beim nächsten App-Start bestehen. Mit MMKV im Vergleich zu LocalStorage im Web können Sie auch Ihre Daten verschlüsseln und mehrere Instanzen haben! 
Verwenden Sie React-Native-Blurhash, um schöne verschwommene Platzhalter für Ihre Bilder und Videos zu zeigen. Generieren Sie eine kurze Zeichenfolge, die eine verschwommene Version Ihres Inhalts ("Blurhash") serverseitig darstellt, und senden Sie sie mit Ihren Daten an die App! 
Wenn Sie dem Benutzer Zahlen präsentieren, sollten Sie diese im richtigen Gebietsschema (Kommas, Währungszeichen, ..) formatieren, während .Tolocalestring (..) seinen Job macht, können Sie Ihre eigene NumberFormat -Instanz tatsächlich konstruieren, um die Leistung um ~ 2x zu verbessern! 
Bewältigen Sie immer den sicheren Bereich angemessen angemessen. Anstatt den gesamten Bildschirm in a zu wickeln, können Sie mit Paddings arbeiten, um eine sauberere Benutzeroberfläche zu erstellen.
Hier haben wir contentContainerStyle={{ paddingBottom: safeAreaBottom }} an den:
Lesen Sie "Effektiv moderne C ++". Auch wenn Sie kein C ++ - Entwickler sind, hilft Ihnen dieses Buch zu verstehen, wie das Gedächtnismanagement funktioniert, und glauben, dass dies beeinflusst, wie Sie über React (nativ) denken. Tatsächlich ist das das einzige Programmierbuch, das ich jemals gelesen habe
Sie werden verstehen, warum {} === {} falsch ist, wie die Gleichstellung der Identität funktioniert, wie Umstände unzählige Zuteilungen sind, wie man Kopien vermeidet, und viele andere Dinge über die Leistung, die Sie beim Schreiben von Code nur ein bisschen anders denken. Optimieren Sie einfach nicht vorzeitig?
Und wenn Sie mit JSI in die C ++ - Entwicklung gehen möchten, ist es noch besser, dass Sie dieses Buch lesen - C ++ ist nicht so verzeihend wie JS. Wenn Sie eine Bibliothek erstellen, die einen schlechten C ++ - Code enthält, werden Benutzer Sie hassen, weil sie ihre App sigabrt gemacht haben?
Verwenden Sie die Komponente niemals direkt. Erstellen Sie stattdessen Ihre eigene Abstraktion, damit Sie sich jedes Mal nicht mit Schriftstellennamen, Schriftgröße oder Farben wiederholen, und es ist einfacher, die Eigenschaften zu einem beliebigen Punkt zu ändern.
Erstellen Sie außerdem eine Eslint -Regel, um Sie jedes Mal zu warnen, wenn Sie versuchen, anstelle von ️ zu verwenden 
Verwenden Sie beim Umgang mit großen Zahlen React-Native-Bignumber anstelle einer der JS-basierten Bibliotheken. ⚡️ Es wird durch eine reine C ++ - Implementierung unterstützt und ist ~ 330x schneller als Bn.js in bestimmten Anwendungen (z. B. #Crypto -Apps, ethers.js, elliptisch, bitcoin) 
Verwenden Sie bei der Arbeit mit #Crypto / Cryptography React-native-Quick-Krypto anstelle einer der JS-basierten Bibliotheken. ⚡️ Es wird durch eine reine C ++-Implementierung unterstützt und ist in bestimmten Szenarien bis zu 58x schneller als React-nativ-Krypto oder Krypto-Browserify.
Sie können die Taschenlampe verwenden, um eine Leistungsbewertung für Ihre Android -App zu generieren
Sie können Profilerstellung zur Leistungsoptimierung durchführen.
Sie sollten console.log aus der prod -App entfernen, wie die Anweisungen von console.log die FPS senken. Sie können Console.log entfernen, indem Sie dies lesen
Vielen Dank an Marc Rousavy und Margelo, da meistens Best Practices ihre sind