
React-Native-Best-PracticeはReact-Native Best Practiceとパッケージであり、パフォーマンスを向上させるための技術とアプリのパフォーマンスを向上させるためのユーティリティを提供します
潜在的に回避可能な再レンダーについて通知する理由を使用する必要があります。
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/,
] ,
} ) ;
}上記のファイルコードをApp root index.jsにインポートします
小道具が変更されていない場合、コンポーネントの再レンダリングをスキップできます。
すべてのレンダリングで再作成されないように、重い計算と配列とオブジェクトの作成をメモ化することが重要です。再レンダーは、状態が変更され、Reduxが何らかのアクションを派遣したとき、またはユーザーがテキスト入力に入力したときに発生します(キープレスごとに再レンダリングします)。非常に明白な理由でレンダリングで多くの操作を実行したくないので、重いフィルタリング、リスト操作などはありません。
純粋なコンポーネント(またはReact.memoコンポーネント)は、小道具が浅い場合、再レンダリングしません。
レンダリング関数で作成する各変数は、各レンダリングで再アロークされます。これは値タイプの問題ではありませんが、これにより、すべてのレンダリングで参照タイプが異なります。これらの変数を小道具を介して純粋なコンポーネントに渡すと、小道具が論理的に同じであるにもかかわらず、再レンダリングを再実行します。多くの場合、これらの変数はブリッジを越えてアプリを遅くします。
純粋なコンポーネントの再レンダーの場合、以前の小道具を現在の小道具と比較し、それらが浅いかどうかをチェックします。
数字、文字列、ブーリアンは価値タイプです。つまり、値で比較できます。
const i1 = 7 ;
const i2 = 7 ;
const equal = i1 === i2 ; // trueオブジェクト、配列、関数は参照タイプです。つまり、論理値で比較することはできませんが、参照で比較する必要があります。
const o1 = { x : 7 } ;
const o2 = { x : 7 } ;
const equal = o1 === o2 ; // false参照比較は、変数のメモリアドレスを単純に比較するため、上記のコードの例ではo1 === o1のみがtrueます。
「React-Native-Best-Practice
from不平等」は、実際の平等によってオブジェクトを比較することですが、それはもはや浅い平等ではありません。
レンダリング関数にオブジェクトを作成すると、すべてのレンダリングで再作成されます。これは、最初のレンダリングでオブジェクトを作成する場合、2番目のレンダリングのオブジェクトに等しくないことを意味します。このため、メモが存在します。
useMemoフックを使用して、依存関係(2番目の引数)が同じままである限り、参照平等を保持する(および各レンダリングで再作成されない)アレイとオブジェクトをメモ化します。また、 useMemoを使用して、配列操作、フィルタリングなどの重い計算をキャッシュします。useCallbackフックを使用して、関数をメモ化します。useDeepEffect 、 useDeepCallback 、 useDeepImperativeHandle 、およびuseDeepLayoutEffect from import {useDeepEffect, ...} from 'react-native-best-practice'使用できます。一般に、フックの概念により、関数コンポーネントをより簡単に最適化できます。ただし、クラスコンポーネントに同様の手法を適用できます。これにより、より多くのコードが発生することに注意してください。
アニメーションとパフォーマンス集中タスクはネイティブスレッドでスケジュールされていますが、ビジネスロジック全体が単一のJavaScriptスレッドで実行されているため、できるだけ少ない作業を行っていることを確認してください。 JavaScriptスレッドであまりにも多くの作業を行うことは、ビデオゲームの高いPingと比較できます。まだスムーズに見ることができますが、すべてのインタラクションが時間がかかりすぎるため、ゲームをプレイすることはできません。
ネイティブコンポーネント( <View> 、 <Text> 、 <Image> 、 <Blurhash> 、...)は、ブリッジを介して小道具をネイティブに渡す必要があります。それらをメモ化することができるので、Reactは浅い平等の小道具を比較し、最後のレンダリングの小道具とは異なる場合にのみ橋の上に通過します。正しくメモ化しない場合は、レンダリングごとに橋の上に小道具を渡すことで、橋が非常に占有されます。スタイルの例を参照してください - スタイルはすべての再レンダーのブリッジの上に送られます!
JavaScriptスレッドであまりにも多くの作業を行わないようにするのに役立ついくつかの例を次に示します。
return < View style = { [ styles . container , { backgroundColor : 'red' } ] } /> ; const style = useMemo ( ( ) => [ styles . container , { backgroundColor : 'red' } ] , [ ] ) ;
return < View style = { style } /> ;useAnimatedStyleからの蘇生スタイル。 レンダラーでfilter 、 map 、またはその他の配列操作を使用すると、レンダリングごとに操作全体が再度実行されます。
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 > ;これを適用して、 .mapで複数のReactビューをレンダリングすることもできます。それらはuseMemoにもメモ化できます。
return < View onLayout = { ( layout ) => console . log ( layout ) } /> ; const onLayout = useCallback ( ( layout ) => {
console . log ( layout ) ;
} , [ ] ) ;
return < View onLayout = { onLayout } /> ; Rendererの他の呼び出しについても必ず考えてください。例えば、 useSelector 、 useComponentDidAppearコールバックをラップしてください!
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 } /> ;
}これは、コンポーネントの状態または小道具に依存しない関数だけでなく、オブジェクトにも適用されます。 useMemoやuseCallbackよりもさらに効率的であるため、できる限りこれを使用してください。
const [ me , setMe ] = useState ( users . find ( ( u ) => u . id === myUserId ) ) ; const [ me , setMe ] = useState ( ( ) => users . find ( ( u ) => u . id === myUserId ) ) ; useStateフックは、初期化の関数を受け入れます。最初の例(「悪い」)はすべてのレンダリングで.findを実行しますが、2番目の例は、状態を初期化するために合格関数を1回実行します。
新しいコンポーネントを書くとき、私は常にレンダリング関数にログステートメントを配置して、コンポーネントに取り組んでいる間に再レンダーを再レンダーする頻度を受動的に視聴します。一般に、コンポーネントはできるだけ少なく再レンダリングする必要があります。コンソールに多くのログが表示されているのを見れば、何か間違ったことをしたことがわかります。作業を開始したら、この関数をコンポーネントに配置し、完了したら削除するのは良い協定です。
function ComponentImWorkingOn ( ) {
// code
console . log ( 're-rendering ComponentImWorkingOn!' ) ;
return < View /> ;
}また、Why-Did-You Renderライブラリを使用して、コンポーネントが再レンダリング(プロップ変更、状態変更など)を確認し、早期にミスをキャッチする理由を確認することもできます。
React.memo export const MyComponent = ( props ) => {
return ...
} const MyComponentImpl = ( props ) => {
return ...
}
export const MyComponent = React . memo ( MyComponentImpl ) ;コンポーネントが同じプロップを与えられて同じ結果をレンダリングする場合、結果をメモ化することにより、パフォーマンスを後押しするためにReact.memo(...)への呼び出しに包むことができます。これは、Reactがコンポーネントのレンダリングをスキップし、最後のレンダリング結果を再利用することを意味します。 React.memoの公式ドキュメントを参照し、 React.memo(...)を賢く使用します。
アプリが遅い場合は、React-Native-Performance Libraryを試してみてください。Plipperプラグインは、インタラクティブまでの時間、コンポーネントのレンダリング時間、スクリプト実行など、さまざまな側面でアプリのパフォーマンスをプロファイルします。
早期に最適化しないでください。ここで使用されるいくつかの例( useMemo Oneなど)は非常に小さく、アイデアのみを示しています。 「usememoのようなフックには、コスト(関数とDEPSアレイの割り当て、実際のフックを呼び出して配列比較を実行する)も伴うため、コンポーネント自体が最適化されている場合はオブジェクトまたは配列を直接通過する方が良いことが多いことに注意してください。特定のコンポーネントの複雑さまたは特定の依存関係グラフを使用した後、メモ機能は大きなパフォーマンスの勝利になる可能性がありますが、不必要に複雑なコードにつながり、パフォーマンスがさらに悪化する場合もあります。前後に常にベンチマーク!
npm i react-native-best-practice
ネイティブのReact Hooksのようなすべての渡された引数
import {useDeepEffect} from 'react-native-best-practice'
useDeepEffect(()=>{
},[recreatedDeepObject])
useDeepEffect => useEffectuseDeepMemo => useMemouseDeepCallback => useCallbackuseDeepImperativeHandle => useImperativeHandleuseDeepLayoutEffect => useLayoutEffectisEqual =>はISequalを深くチェックしますcloneDeep =>はオブジェクトと配列を深くクローンしますUIフレームレートとJSフレームレートを示すため、アプリの開発中は常にプリフェートモニターをオンにします。フレームがドロップする場合は、フレームをドロップし、インタラクティブ(TTI)を低くするための新しいコードを確認できます。アプリでDev Menuを開き、 Show Perf Monitorを開きます。 
フラットリストを使用しないでください。リサイクルビューの概念を使用するため、フラッシュリストを使用してください。このビューは、画面に表示される限られた数のビューを作成およびレンダリングするだけです。
カスタムロガーインスタンスを作成し、絵文字を強制してログを分類します。これにより、コンソールで関連するラインを見つける方が簡単で、全体的にはよりフレンドリーに見えます。たくさんのログをして、後の時点でデバッグの長い夜から自分自身を救ってください! 
@ReactNavigationのネイティブスタックを常に使用してください。 Platform-Native Screen Primitivesを使用しているため、ほとんどの場合、JSベースのスタックよりもパフォーマンスが向上する価値があります。 
Redux既にReduxを使用している場合は、メモ化された「セレクター」関数に再選択する必要があります
Reactコンテキスト既にReactコンテキストを使用している場合は、Memoized「セレクター」関数にuse-context-selectorを使用する必要があります。そうしないと、コンテキスト値が変更されます。
これらのLibs Recoil、Jotai Zustandを国家管理に使用することをお勧めします
親コンポーネントから子供コンポーネントで何かをする必要がある場合は、子コンポーネントから遊ぶ代わりに、親コンポーネントから子コンポーネント関数を呼び出すためにRefとuseimperativeHandleを使用してください。
アプリをスピードアップするためにたくさんのバッファーを扱うときは、@craftzdogのReact-Native-Bufferフォークを使用します。 JSIを介して公開されたC ++バックされた実装を使用します。これは、JSベースの実装よりも約4倍高速です。 
React-Native-MMKVを使用して、次のアプリの起動にも続くローカルストレージからデータを同期して保存および取得します。 Web上のLocalStorageと比較して、MMKVではデータを暗号化して複数のインスタンスを持つこともできます。 
React-Native-Blurhashを使用して、画像やビデオに美しいぼやけたプレースホルダーを表示します。コンテンツのぼやけたバージョン(「Blurhash」)サーバー側を表す短い文字列を生成し、データと一緒にアプリに送信します! 
ユーザーに番号を提示する場合、正しいロケール(コンマ、通貨標識など)にフォーマットする必要がありますが、.tolocalestring(..)がジョブである場合、実際に独自のNumberformatインスタンスを構築してパフォーマンスを〜2倍改善できます。 
常に安全なエリアインセットを適切に処理してください。画面全体をAでラッピングする代わりに、パディングを使用してクリーンなUIを作成できます。
ここでは、 contentContainerStyle={{ paddingBottom: safeAreaBottom }}を渡しました。
「効果的な最新のC ++」を読んでください。あなたがC ++開発者でなくても、この本は、メモリ管理の仕組みを理解し、それを信じているかどうかを理解するのに役立ちます。実際、それは私が今まで読んだ唯一のプログラミング本です
{} ==== {}が誤っている理由、アイデンティティの平等の仕組み、再レンダーがどのように割り当てられているか、コピーを避ける方法、およびコードを書くときに少し違うと思うパフォーマンスに関する他の多くのものがわかります。時期尚早に最適化しないでください。
また、JSIでC ++開発に進みたい場合は、この本を読む方がさらに良いことです。C++はJSほど寛容ではありません。 C ++コードが悪いライブラリを作成した場合、ユーザーはアプリSigabrtを作成することであなたを嫌うでしょうか?
コンポーネントを直接使用しないでください。代わりに、独自の抽象化を作成して、毎回フォント名、フォントサイズ、または色で自分自身を繰り返さないようにしてください。
さらに、ESLINTルールを作成して、§の代わりに使用しようとしているたびに警告します
多数を扱うときは、JSベースのライブラリの代わりにReact-Native-Bignumberを使用します。 pure C ++実装に裏付けられており、特定のアプリケーションではbn.jsよりも〜330倍高速です(#cryptoアプリ、ethers.js、elliptic、bitcoinなど) 
#Crypto /暗号化を使用する場合は、JSベースのライブラリではなく、React-Native-Quick-Cryptoを使用してください。 pureこれは純粋なC ++の実装に裏付けられており、特定のシナリオでReact-Native-ClyptoまたはCrypto-Browsifyよりも最大58倍高速です。
懐中電灯を使用して、Androidアプリのパフォーマンススコアを生成できます
パフォーマンスの最適化のためにプロファイリングを行うことができます。
console.logステートメントを使用してfpsを使用するように、prodアプリからconsole.logを削除する必要があります。これを読んでconsole.logを削除できます
ほとんどのベストプラクティスは彼らのものです。