
反應最佳實踐是一種反應的最佳實踐和一個包裝,它為提高性能以及提高應用程序性能的實用程序提供了技術
您應該使用為什麼會向您通知您有可能避免的重新訂單的原因。
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/,
] ,
} ) ;
}將上述文件代碼導入您的應用程序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 。
“
from反應最佳練習中相等,可以通過實際平等比較對象,但這不再是淺薄的平等。
如果您在渲染函數中創建對象,則將在每個渲染上重新創建它們。這意味著,當您在第一個渲染中創建一個對象時,它不與第二播放中的對象相等。出於這個原因,存在回憶。
useMemo鉤記錄數組和對象,只要依賴項(第二個參數)保持不變,這些數組和對象將保持其參考平等(並且不會在每個渲染上重新創建)。還使用useMemo來緩存重量計算,例如數組操作,過濾等。useCallback鉤記錄功能。useDeepEffect -native-best-best-test- useDeepImperativeHandle {undereepeffect,...}從'react-native-best-best-test-practice'import ofimperepcallback, useDeepCallback ,usedeepimperativeHandle和useDeepLayoutEffect import {useDeepEffect, ...} from 'react-native-best-practice'通常,由於鉤子的概念,可以更容易地優化功能組件。但是,您可以為類組件應用類似的技術,請注意,這將導致更多代碼。
儘管動畫和性能密集型任務安排在本機線程上,但您的整個業務邏輯都在單個JavaScript線程上運行,因此請確保您在那裡做的工作盡可能少。可以將在JavaScript線程上進行太多工作與視頻遊戲中的高ping進行比較 - 您仍然可以順利環顧四周,但是您不能真正玩遊戲,因為每個互動都花費太長。
本機組件( <View> , <Text> , <Image> , <Blurhash> ,...)必須通過橋傳遞給本機。它們可以回憶,因此反應比較淺平等的道具,只有在它們與最後渲染的道具不同的情況下,它們只會將它們通過橋樑。如果您沒有正確記憶,則可能會為每一個渲染而在橋上傳遞道具,從而導致橋樑非常佔據。請參閱樣式示例 - 樣式將在每個重新渲染的橋樑上發送!
以下是一些示例,可以幫助您避免在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 } /> ;請確保還考慮渲染器中的其他呼叫,例如,EG 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輸入,但第二個示例僅運行傳遞的函數一次以初始化狀態。
在編寫新組件時,我總是在渲染函數中放置日誌語句,以被動地觀察我的組件重新訂閱量的頻率。通常,組件應盡可能少地呈現,如果我看到很多日誌出現在我的控制台中,我知道我做錯了什麼。一旦開始處理該功能,將此功能放入組件中是一個很好的典型,然後將其刪除後。
function ComponentImWorkingOn ( ) {
// code
console . log ( 're-rendering ComponentImWorkingOn!' ) ;
return < View /> ;
}您還可以使用Why-Did-you-render庫來找出組件重新渲染的原因(Prop更改,狀態更改,...),並可能儘早捕獲錯誤。
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-tormformance庫,並且是Flipper插件,以在各個方面(例如時間交互式,組件渲染時間,腳本執行等)在各個方面介紹您的應用程序性能。
不要過早優化。這裡使用的一些示例(例如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 =>將深入檢查我cloneDeep =>將克隆對象和數組深在開發應用程序時,請務必打開PERF監視器,因為它會告訴您UI Framerate和JS Framerate,如果有任何框架下降,則可以檢查哪些新代碼導致掉落幀並使您的時間進行交互式(TTI)低點,您可以在應用程序中打開Dev Menu ,並toggle Show Perf Monitor 。 
切勿使用flatlist,始終使用flashlist,因為它使用回收視圖的概念,該概念僅創建並渲染屏幕上可見的數量有限的視圖
創建一個自定義Logger實例,並強制執行表情符號以對日誌進行分類。這樣,在您的控制台中發現相關的線條更容易,並且整體看起來更友好。進行大量伐木,以免稍後的漫長的調試夜! 
始終使用@reaectnavigation中的本機堆棧。由於它使用了平臺本地屏幕原始圖,因此與基於JS的堆棧相比,它幾乎總是值得的。 
redux如果您已經使用了redux,則應將重新選擇用於記憶的“選擇器”功能
React上下文如果您已經使用了React上下文,則應將使用使用用戶使用selecter用於記憶的“選擇器”功能,否則上下文值已更改,USECONTEXT將重新渲染的所有組件。
建議使用這些Libs後坐力,Jotai Zustand進行國家管理
如果您需要從父零件中做一些子組件中的操作
在處理大量緩衝區以加快應用程序時,請使用@CraftzDog的React-Native-Buffer叉。它使用通過JSI暴露的C ++支持的實現,該實現比基於JS的實現快4倍。 
使用React-Native-MMKV同步存儲和從本地存儲中檢索數據,即使在下一個應用程序啟動中,這些數據仍然存在。與Web上的LocalStorage相比,MMKV還允許您加密數據並具有多個實例! 
使用React-Native-Blurhash為您的圖像和視頻展示美麗的模糊佔位符。生成一個簡短的字符串,該字符串代表您的內容(“ Blurhash”)服務器端的模糊版本,並將其與您的數據一起發送到應用程序! 
在向用戶提交數字時,您應該在正確的語言環境(逗號,貨幣標誌,..)中格式化它們,而.toleocalestring(..)確實可以做到這一點,您實際上可以構建自己的numberFormat實例,以提高性能〜2x! 
始終適當處理安全區域插圖。您可以使用槳板來創建更清潔的UI,而不是將整個屏幕包裹在A中。
在這裡,我們將contentContainerStyle={{ paddingBottom: safeAreaBottom }}傳遞給:
閱讀“有效的現代C ++”。即使您不是C ++開發人員,這本書也將幫助您了解內存管理的工作原理並相信這會影響您對React(本地)的看法。實際上,這是我讀過的唯一一本編程書
您將了解為什麼{} === {}是錯誤的,身份等效的工作原理,重新渲染的方式是大量的分配,如何避免副本以及有關性能的許多其他內容,這些內容使您在編寫代碼時會有些不同。只是不要過早優化?
而且,如果您想與JSI一起進入C ++開發,那麼您閱讀本書就更好了-C ++不像JS那樣寬容。如果您製作的庫中的C ++代碼不好,用戶會討厭您製作其應用程序Sigabrt?
切勿直接使用組件。相反,創建自己的抽象,這樣您就不會每次都使用字體名稱,字體大小或顏色重複自己,並且在任何時候都更容易更改屬性。
此外,創建一個ESLINT規則,以警告您每次嘗試使用而不是使用
在處理大量時,請使用反應本機式信徒,而不是基於JS的任何庫。 ⚡️它得到了純C ++實現的支持,並且在某些應用程序中比BN.js快〜330x(例如#Crypto Apps,Ethers.js,Elliptic,Bitcoin) 
使用#Crypto / Cryptography時,請使用React-Native-Quick-Crypto代替任何基於JS的庫。 ⚡️它得到了純C ++實現的支持,在某些情況下,比React-native-crypto或Crypto-Browserify快58倍。
您可以使用手電筒為您的Android應用程序生成性能得分
您可以進行分析以進行性能優化。
您應該使用console.log語句降低fps,從prod應用程序中刪除console.log ,您可以通過閱讀此信息刪除Console.log
多虧了馬克·魯薩維(Marc Rousavy)和瑪格洛(Margelo),這主要是最好的做法