React?Native性能優(yōu)化紅寶書(shū)方案詳解
一、React Native介紹
React Native 是Facebook在React.js Conf2015 推出的開(kāi)源框架,使用React和應(yīng)用平臺(tái)的原生功能來(lái)構(gòu)建 Android 和 iOS 應(yīng)用。通過(guò) React Native,可以使用 JavaScript 來(lái)訪問(wèn)移動(dòng)平臺(tái)的 API,使用 React 組件來(lái)描述 UI 的外觀和行為。
JS實(shí)現(xiàn)調(diào)用的能力中間的適配層提供了一些橋接方案
1、RN優(yōu)勢(shì)
1.1 HTML/CSS/JS開(kāi)發(fā)成本低,用統(tǒng)一的代碼規(guī)范開(kāi)發(fā)移動(dòng)端程序,不用關(guān)注移動(dòng)端差異
1.2 天然跨平臺(tái),開(kāi)發(fā)一次,可以生成Android和ios兩個(gè)系統(tǒng)上的APP,這減少了開(kāi)發(fā)人員需要編寫(xiě)不同版本的應(yīng)用程序的時(shí)間和工作量。
1.3 無(wú)審核熱更新
1.4 可擴(kuò)展
1.5 易學(xué)易用:React Native 基于 React,開(kāi)發(fā)人員可以使用熟悉的 JavaScript 和 React 組件模型來(lái)構(gòu)建應(yīng)用程序,因此很容易學(xué)習(xí)和上手。
RN的本質(zhì)是把中間的這個(gè)橋Bridge給搭好,讓JS和native可以互相調(diào)用。
RN為我們提供了JS的運(yùn)行環(huán)境,所以前端開(kāi)發(fā)者們只需要關(guān)心如何編寫(xiě)JS代碼,
畫(huà)UI只需要畫(huà)到virtual DOM 中,不需要特別關(guān)心具體的平臺(tái)。
至于如何把JS代碼轉(zhuǎn)成native代碼的臟活累活,RN底層全干了
2、RN劣勢(shì)
2.1 不成熟,項(xiàng)目版本更新維護(hù)較頻繁,學(xué)習(xí)成本高,試錯(cuò)成本高,有些問(wèn)題較少解決方案,開(kāi)發(fā)進(jìn)度慢
2.2 性能:整體性能仍不如原生
2.3 兼容性:涉及底層的功能,需要針對(duì)Android和ios雙端單獨(dú)開(kāi)發(fā)
2.4 有限的第三方庫(kù):盡管 React Native 社區(qū)不斷增長(zhǎng),但相對(duì)于其他混合應(yīng)用框架,第三方庫(kù)和插件的數(shù)量還是有限的。這可能使開(kāi)發(fā)人員在某些方面受到限制。
2.5 有些原生功能需要自己實(shí)現(xiàn):雖然 React Native 提供了大量原生組件,但某些原生功能需要開(kāi)發(fā)人員自己實(shí)現(xiàn),這可能需要額外的時(shí)間和工作量。
3、跨平臺(tái)框架比較
開(kāi)發(fā)模式 | 原生開(kāi)發(fā) | 混合開(kāi)發(fā) | Web開(kāi)發(fā) |
運(yùn)行環(huán)境 | Android、iOS、Windows | 混合App、 React Native,Weex、Flutter | 瀏覽器、WebView |
編程語(yǔ)言 | Java,Objective-C | JavaScript、Dart | HTML、CSS、JavaScript |
可移植性 | 差 | 一般 | 好 |
開(kāi)發(fā)速度 | 慢 | 一般 | 快 |
性能 | 快 | 一般 | 慢 |
學(xué)習(xí)成本 | 高 | 一般 | 低 |
4、Hybrid App 優(yōu)勢(shì)
4.1 跨平臺(tái)開(kāi)發(fā)
4.2 離線訪問(wèn)
4.3 原生應(yīng)用程序的用戶體驗(yàn)
4.4 快速開(kāi)發(fā)和迭代
混合應(yīng)用程序結(jié)合了Web應(yīng)用程序和本地應(yīng)用程序的優(yōu)點(diǎn),既能夠在原生應(yīng)用程序環(huán)境中運(yùn)行,也能夠在 Web 瀏覽器中運(yùn)行,并且具有更好的用戶體驗(yàn)和功能。這種開(kāi)發(fā)方式可以大大減少開(kāi)發(fā)時(shí)間和成本,提高開(kāi)發(fā)效率。
5、React Native 0.68之前的架構(gòu)
5.1、整體UI渲染太過(guò)于依賴JsBridge,容易出現(xiàn)阻塞影響整體UI體驗(yàn)
5.2、性能和問(wèn)題反饋?zhàn)畲蟮慕M件:
ScrollView:一次渲染不做任何回收,啟動(dòng)性能慢,占用內(nèi)存大
FlatList:做了組件回收,快速滑動(dòng)中容易出現(xiàn)白屏和卡頓
Shadow層最終呈現(xiàn)到原生的UI是異步的,滑動(dòng)太快會(huì)有大量的UI
5.3、事件阻塞在JsBridge,導(dǎo)致了長(zhǎng)時(shí)間白屏的出現(xiàn)
6、RN中的視圖渲染
javascript:JS代碼的執(zhí)行線程,將源碼通過(guò)Metro打包后傳給JS引擎進(jìn)行解析:
結(jié)構(gòu) 樣式 屬性
Main線程(UI線程或原生線程):主要負(fù)責(zé)原生渲染(Native UI)和調(diào)用原生模塊(Native Modules Shadow 線程Layout線程:創(chuàng)建Shadow Tree來(lái)模擬Reac結(jié)構(gòu)樹(shù)(類似虛擬DOM),再由Yoga引擎將Flexbox等樣式,解析成平臺(tái)的布局方式:
寬高 位置
7、RN架構(gòu)設(shè)計(jì)--新舊架構(gòu)對(duì)比
7.1、JavaScript層:
支持React 16+新特性
增強(qiáng)JS靜態(tài)類型檢查(CodeGen)
引入JSI允許替換不同的JavaScript引擎
7.2、Bridge層:
劃分了Fabric和TurboModules,分別負(fù)責(zé)管理UI和Native模塊
7.3、Native層:
精簡(jiǎn)核心模塊,將非核心部分拆除去,作為社區(qū)模塊,獨(dú)立維護(hù)
8、從 0.68 版本開(kāi)始React Native 的新架構(gòu)
8.1、JSI (JavaScript Interface)
一個(gè)用 C++ 寫(xiě)成的輕量級(jí)框架
實(shí)現(xiàn)JS引擎的互換
通過(guò)JS直接調(diào)用Native
減少不必要的線程通信,省去序列化和反序列化的成本,
減輕了通信壓力,提高了通信性能
8.2、CodeGen
FaceBook推出的代碼生成工具
加入了類型約束后,減少了數(shù)據(jù)類型錯(cuò)誤
自動(dòng)將 Flow 或 TS 有靜態(tài)類型檢查的 JS 代碼轉(zhuǎn)換為 Fabric 和 TurboModules 使用的原生代碼
8.3、優(yōu)化Bridge層
Fabric是整個(gè)框架中的新UI層,簡(jiǎn)化了之前的渲染
Turbo Modules通過(guò)JSI可以讓JS直接調(diào)用Native模塊,實(shí)現(xiàn)同步操作,實(shí)現(xiàn)Native模塊按需加載,減少啟動(dòng)時(shí)間,提高性能
8.4、精簡(jiǎn)核心代碼(LEAN Core)
將React Native核心包進(jìn)行瘦身,非必要包移到社區(qū)單獨(dú)維護(hù)
9、React介紹
Facebook,Learn Once,write anywhere
數(shù)據(jù)驅(qū)動(dòng),狀態(tài)決定界面的變化,虛擬dom(抽象層)
虛擬dom的好處,首先是性能的優(yōu)化,不直接操作Dom先進(jìn)行一些比較,計(jì)算找出需要變化的部分,在實(shí)際的dom中進(jìn)行操作
其次,這個(gè)抽象層,還提供了邏輯代碼跨平臺(tái)移植的可能性
虛擬dom的下方對(duì)接的,是網(wǎng)頁(yè),是移動(dòng)端,是電視端,任何一個(gè)可以渲染的端,都可以做接口的適配,使得代碼在任何地方使用
主要四個(gè)部分:
組件:類組件、函數(shù)式組件
屬性Props
狀態(tài)State
jsx:React 和 React Native 都使用JSX 語(yǔ)法,這種語(yǔ)法使得你可以在 JavaScript 中直接輸出本質(zhì)上也就是 JavaScript,所以你可以在其中直接使用變量元素,JSX
hook api: todo補(bǔ)充
生命周期: todo補(bǔ)充
二、性能優(yōu)化點(diǎn)
1、RN加載的主要時(shí)間消耗
todo:補(bǔ)充
2、RN性能優(yōu)化-拆包、分包
React Native 頁(yè)面的 JavaScript 代碼包是熱更新平臺(tái)根據(jù)版本號(hào)進(jìn)行下發(fā)的,每次有業(yè)務(wù)改動(dòng),我們都需要通過(guò)網(wǎng)絡(luò)請(qǐng)求更新代碼包。
因此,我們?cè)趯?duì)JavaScript 代碼進(jìn)行打包的時(shí)候,需要將包拆分成兩個(gè)部分:
2.1、Common 部分,也就是 React Native 源碼部分;
2.2、業(yè)務(wù)代碼部分,也就是我們需要?jiǎng)討B(tài)下載的部分
具體操作:
JavaScript 代碼包中 React Native 源碼相關(guān)的部分是不會(huì)發(fā)生變化的,所以我們不需要在每次業(yè)務(wù)包更新的時(shí)候都進(jìn)行下發(fā),在工程中內(nèi)置一份就好了。Common 包內(nèi)置到工程中業(yè)務(wù)代碼包進(jìn)行動(dòng)態(tài)下載利用 JSContext 環(huán)境,在進(jìn)入載體頁(yè)后在環(huán)境中先加載 Common 包,再加載業(yè)務(wù)代碼包就可以完整的渲染出 React Native 頁(yè)面
todo:代碼示例?
3、首屏渲染
通過(guò)拆包的方案,已經(jīng)減少了動(dòng)態(tài)下載的業(yè)務(wù)代碼包的大小。但是還會(huì)存在部分業(yè)務(wù)非常龐大,拆包后業(yè)務(wù)代碼包的大小依然很大的情況,依然會(huì)導(dǎo)致下載速度較慢,并且還會(huì)受網(wǎng)絡(luò)情況的影響。
因此,我們可以再次針對(duì)業(yè)務(wù)代碼包進(jìn)行拆分
將一個(gè)業(yè)務(wù)代碼包拆分為一個(gè)主包和多個(gè)子包的方式
在進(jìn)入頁(yè)面后優(yōu)先請(qǐng)求主包的 JavaScript 代碼資源,能夠快速地渲染首屏頁(yè)面,
緊接著用戶點(diǎn)擊某一個(gè)模塊時(shí),再繼續(xù)下載對(duì)應(yīng)模塊的代碼包并進(jìn)行渲染,就能再進(jìn)一步減少加載時(shí)間。
4、減少渲染的節(jié)點(diǎn)-通過(guò)組件懶加載提高應(yīng)用性能
組件懶加載可以讓 react 應(yīng)用在真正需要展示這個(gè)組件的時(shí)候再去展示,有效的減少渲染的節(jié)點(diǎn)數(shù),提高頁(yè)面的加載速度
React 官方在 16.6 版本后引入了新的特性:React.lazy 和 React.Suspense,這兩個(gè)組件的配合使用可以比較方便進(jìn)行組件懶加載的實(shí)現(xiàn)
React.lazy 該方法主要的作用就是可以定義一個(gè)動(dòng)態(tài)加載的組件,這可以直接縮減打包后 bundle 的體積,
并且可以延遲加載在初次渲染時(shí)不需要渲染的組件
Suspense組件中的 fallback 屬性接受任何在組件加載過(guò)程中你想展示的 React 元素。
你可以將 Suspense 組件置于懶加載組件之上的任何位置,你甚至可以用一個(gè) Suspense 組件包裹多個(gè)懶加載組件。 代碼示例如下:
import React, {Suspense} from 'react'; const OtherComponent = React.lazy(() => import('./OtherComponent)); const AnotherComponent = React.lazy(() => import('./AnotherComponent)); function MyComponent() { return( <div> <Suspense fallback={<div> loading...</div>}> <section> <OtherComponent/> <AnotherComponent/> </section> </Suspense> </div> ) }
使用懶加載可以減少bundle文件大小,
不同的文件打包到不同的頁(yè)面組件當(dāng)中,加快組件的呈現(xiàn)
import React, {lazy, Suspense} from 'react'; const OtherComponentLazy = lazy(() => import('./OtherComponent)); const AnotherComponentLazy = lazy(() => import('./AnotherComponent)); function Suspensed(lazyComponent) { return (props) { <Suspense fallback={<div></div>}> <lazyComponent {...props} /> </Suspense> } } export const OtherComponent = Suspensed(OtherComponentLazy) export const AnotherComponent = Suspensed(AnotherComponentLazy)
5、提交階段優(yōu)化-避免重復(fù)無(wú)限渲染
當(dāng)應(yīng)用程序狀態(tài)發(fā)生更改時(shí),React會(huì)調(diào)用render方法。
如果在render方法中繼續(xù)更改應(yīng)用程序狀態(tài),就會(huì)發(fā)生render方法遞歸調(diào)用,導(dǎo)致應(yīng)用報(bào)錯(cuò)。
Render方法應(yīng)該作為純函數(shù),render方法的執(zhí)行要根據(jù)狀態(tài)的改變,保持組件的行為和渲染方法一致。
執(zhí)行提交階段鉤子,會(huì)阻塞瀏覽器更新頁(yè)面。
如果在提交階段鉤子函數(shù)中更新組件 State,會(huì)再次觸發(fā)組件的更新流程,造成兩倍耗時(shí)。
一般在提交階段的鉤子中更新組件狀態(tài)的場(chǎng)景有:
- 類組件應(yīng)使用 getDerivedStateFromProps 鉤子方法代替,函數(shù)組件應(yīng)使用函數(shù)調(diào)用時(shí)執(zhí)行 setState的方式代替。
- 使用上面兩種方式后,React 會(huì)將新?tīng)顟B(tài)和派生狀態(tài)在一次更新內(nèi)完成。
- 根據(jù) DOM 信息,修改組件狀態(tài)。在該場(chǎng)景中,除非想辦法不依賴 DOM 信息,否則兩次更新過(guò)程是少不了的,就只能用其他優(yōu)化技巧了。
6、組件卸載前執(zhí)行清理操作
React 組件性能優(yōu)化的核心是減少渲染真實(shí)DOM節(jié)點(diǎn)的頻率,減少Virtual DOM 比對(duì)的頻率
在組件中為window注冊(cè)的全局事件,以及定時(shí)器,在組件卸載前要清理掉,防止組件卸載后繼續(xù)執(zhí)行影響應(yīng)用性能
import React,{ Component } from 'react'; export default class Hello extends Component { componentDidMount() { this.timer = setTimeout( () => { console.log('把一個(gè)定時(shí)器的引用掛在this上'); }, 500 ); } componentWillUnmount() { // 如果存在this.timer,則使用clearTimeout清空。 // 如果你使用多個(gè)timer,那么用多個(gè)變量,或者用個(gè)數(shù)組來(lái)保存引用,然后逐個(gè)clear this.timer && clearTimeout(this.timer); } };
7、通過(guò)使用占位符標(biāo)記提升React組件的渲染性能
使用Fragment不對(duì)應(yīng)具體的視圖,減少了包含的額外標(biāo)記的數(shù)量
僅僅是代表可以包裝而已,跟空的標(biāo)識(shí)符一樣,視圖層級(jí)關(guān)系減少有利于視圖渲染,
滿足在組件頂級(jí)具有單個(gè)父級(jí)的條件
<div> ... </div> // 上面會(huì)多出一個(gè)無(wú)意義標(biāo)記 // 應(yīng)該改為 <fragment> ... </fragment> // 或者寫(xiě)成下面這樣也是可以的 <> ... </>
8、縮小狀態(tài)影響范圍-狀態(tài)下放到使用組件的內(nèi)部
React不直接操作DOM,它在內(nèi)存中維護(hù)一個(gè)快速響應(yīng)的DOM描述,render方法返回一個(gè)DOM的描述
React能夠計(jì)算出兩個(gè)DOM描述的差異,然后更新瀏覽器中的DOM,這就是著名的DOM Diff。
就是說(shuō)React在接收到屬性(props)或者狀態(tài)(state)更新時(shí),就會(huì)通過(guò)前面的方式更新UI。所以React整個(gè)UI渲染是比較快的。但是這里面可能出現(xiàn)的問(wèn)題是:
假設(shè)我們定義一個(gè)父組件,其包含了5000個(gè)子組件。我們有一個(gè)輸入框輸入操作,每次輸入一個(gè)數(shù)字,對(duì)應(yīng)的那個(gè)子組件背景色變紅。
父組件更新默認(rèn)觸發(fā)所有子組件更新,子組件的props為空對(duì)象,{} === {} 永遠(yuǎn)會(huì)返回false
優(yōu)化思想:將變的和不變的分開(kāi)(state,props,context)
我們需要先手動(dòng)創(chuàng)建一個(gè)有嚴(yán)重渲染性能的組件,如下所示:
import { useState } from 'react'; export default function App() { let [color, setColor] = useState('red'); return ( <div> <input value={color} onChange={(e) => setColor(e.target.value)} /> <p style={{ color }}>Hello, world!</p> <ExpensiveTree /> </div> ); } function ExpensiveTree() { let now = performance.now(); while (performance.now() - now < 100) { // Artificial delay -- do nothing for 100ms } return <p>I am a very slow component tree.</p>; }
很顯然,當(dāng) App 組件內(nèi)的狀態(tài)發(fā)生了改變,ExpensiveTree 組件會(huì) re-render, 事實(shí)上 ExpensiveTree 組件的 props、state 并未發(fā)生改變,這并不是我們期望的結(jié)果。
export default function App() { let [color, setColor] = useState('red'); return ( <div> <input value={color} onChange={(e) => setColor(e.target.value)} /> <p style={{ color }}>Hello, world!</p> <ExpensiveTree /> </div> ); }
我們可以看到以上 ExpensiveTree 組件并不依賴 App 組件內(nèi)部的狀態(tài),因此我們是否可以考慮,將依賴 color 的元素抽離到一個(gè)依賴 color 的組件中呢?
export default function App() { return ( <> <Form /> <ExpensiveTree /> </> ); } function Form() { let [color, setColor] = useState('red'); return ( <> <input value={color} onChange={(e) => setColor(e.target.value)} /> <p style={{ color }}>Hello, world!</p> </> ); }
此時(shí),將依賴 color 的元素提取到了 Form 組件中,F(xiàn)orm 組件內(nèi)部的狀態(tài)不再影響 ExpensiveTree 組件的渲染,問(wèn)題便得到了解決。
9、跳過(guò)不必要的組件更新-通過(guò)純組件提升性能
- 類組件中使用PureComponent
- 函數(shù)式組件中使用React.memo
在 React 工作流中,如果只有父組件發(fā)生狀態(tài)更新,即使父組件傳給子組件的所有 Props 都沒(méi)有修改,也會(huì)引起子組件的 Render 過(guò)程。
如果子組件的 Props 和 State 都沒(méi)有改變,那么其生成的 DOM 結(jié)構(gòu)和副作用也不應(yīng)該發(fā)生改變。
純組件會(huì)對(duì)組件輸入數(shù)據(jù)進(jìn)行淺層比較,如果當(dāng)前輸入數(shù)據(jù)和上次輸入數(shù)據(jù)相同,組件不會(huì)重新渲染。
比較引用數(shù)據(jù)類型在內(nèi)存中的引用地址是否相同,比較基本數(shù)據(jù)類型的值是否相同
為什么不直接進(jìn)行diff操作?而要先進(jìn)行淺比較?
淺比較只操作當(dāng)前組件的state和props,diff操作會(huì)重新遍歷整個(gè)VirtualDOM樹(shù)
10、跳過(guò)不必要的組件更新-通過(guò)shouldComponentUpdate
純函數(shù)只能進(jìn)行淺層比較,要進(jìn)行深層比較,
使用shouldComponentUpdate,它用于編寫(xiě)自定義比較邏輯
ShouldComponentUpdate(nextProps,nextState){ if(nextProps……){ return true } return false }
11、跳過(guò)不必要的組件更新-通過(guò)memo純組件提升性能
Memo基本使用:將函數(shù)組件變?yōu)榧兘M件,當(dāng)前props和上一次的props進(jìn)行淺比較,如果相同就阻止組件重新渲染
Memo函數(shù)是淺層數(shù)據(jù)比較,如果遇到引用數(shù)據(jù)類型,需要傳遞自定義比較邏輯,傳給Memo函數(shù)的第二個(gè)參數(shù)
memo的第二個(gè)參數(shù)示例如下:
// 給memo傳遞第二個(gè)參數(shù),自定義比較邏輯 import React, { memo, useEffect, useState } from 'react' function App () { const [person, setPerson] = useState({ name: '張三', age: 20, job: 'waiter' }) const [index, setIndex] = useState(0) useEffect(() => { let timer = setInterval(() => { setIndex(prev => prev + 1) setPerson({ ...person, job: 'chef' }) }, 1000) return () => { clearInterval(timer) } }, [index, person]) return ( <div> {index} <ShowName person={person} /> </div> ) } function compare (prevProps, nextProps) { if ( prevProps.person.name !== nextProps.person.name || prevProps.person.age !== nextProps.person.age ) { return false } return true } const ShowName = memo(function ({ person }) { console.log('render...') return ( <div> {person.name} {person.age} </div> ) }, compare) export default App
12、跳過(guò)不必要的組件更新- useMemo、useCallback緩存優(yōu)化
useMemo、useCallback 實(shí)現(xiàn)穩(wěn)定的 Props 值
useMemo 緩存上次計(jì)算的結(jié)果,當(dāng) useMemo 的依賴未發(fā)生改變時(shí),就不會(huì)觸發(fā)重新計(jì)算,一般用在非常耗時(shí)的場(chǎng)景中,
如:遍歷大列表做統(tǒng)計(jì)信息。
useCallback ,將父組件傳遞給子組件時(shí),子組件會(huì)因?yàn)橹匦聄ender發(fā)生改變的時(shí)候,緩存一個(gè)值
useCallback 是 React 的一個(gè) Hook,它用于記住函數(shù)的引用,避免在每次渲染時(shí)都創(chuàng)建一個(gè)新的函數(shù)實(shí)例。這可以幫助優(yōu)化性能,因?yàn)楸苊獠槐匾闹劁秩竞妥咏M件的重新渲染。
使用場(chǎng)景:
當(dāng)你有一個(gè)函數(shù),它依賴于某些 props 或 state,但你不希望它在這些依賴發(fā)生變化時(shí)重新創(chuàng)建,你可以使用 useCallback 來(lái)保持引用不變。
如果你有一個(gè)子組件,它是純的(不依賴外部狀態(tài),只依賴于傳入的 props),并且你希望避免非必要的重渲染,你可以使用 useCallback 來(lái)保證傳遞給子組件的函數(shù)引用保持不變。
例子代碼:
import React, { useCallback } from 'react'; function ParentComponent() { const [count, setCount] = useState(0); // 使用 useCallback 來(lái)避免在每次渲染時(shí)都創(chuàng)建一個(gè)新的函數(shù)實(shí)例 const incrementCount = useCallback(() => { setCount(count + 1); }, [count]); return ( <div> <p>Count: {count}</p > <button onClick={incrementCount}>Increment</button> ChildComponent onIncrement={incrementCount} /> </div> ); } function ChildComponent({ onIncrement }) { // 這里我們不需要每次 ParentComponent 渲染時(shí)都創(chuàng)建一個(gè)新的函數(shù)實(shí)例 // 因?yàn)?onIncrement 引用沒(méi)有變化 return <button onClick={onIncrement}>Increment from Child</button>; }
在這個(gè)例子中,incrementCount 是一個(gè)函數(shù),用于增加計(jì)數(shù)。我們使用 useCallback 來(lái)保證在 ParentComponent 的多次渲染中,incrementCount 函數(shù)的引用是不變的,這樣 ChildComponent 就不會(huì)因?yàn)?ParentComponent 的渲染而不必要地重新渲染。
13、列表使用Key屬性
遍歷展示視圖時(shí)使用 key,key 幫助 React 識(shí)別哪些元素改變了,比如被添加或刪除。因此你應(yīng)當(dāng)給數(shù)組中的每一個(gè)元素賦予一個(gè)確定的標(biāo)識(shí)
const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((number) => <li key={number.toString()}> {number} </li>);
使用 key 注意事項(xiàng):
這個(gè)元素在列表中擁有的一個(gè)獨(dú)一無(wú)二的字符串。通常,我們使用數(shù)據(jù)中的 id 來(lái)作為元素的 key
14、不要使用內(nèi)聯(lián)函數(shù)定義:
如果使用內(nèi)聯(lián)函數(shù),函數(shù)是引用數(shù)據(jù)類型,在內(nèi)存中的地址不會(huì)相同,則每次render函數(shù)時(shí),都會(huì)創(chuàng)建一個(gè)新的函數(shù)實(shí)例
在渲染階段會(huì)綁定新函數(shù)并將舊實(shí)例扔給垃圾回收,因此綁定內(nèi)聯(lián)函數(shù),需要額外的垃圾回收和綁定到DOM的工作
1.Render(){ Return (<input type=“button” onClick={(e)=>{this.setState({inputVal:e.target.value})}}>) } 2.setNewState=(e)->{this.setState({inputVal:e.target.value})} //箭頭函數(shù)被添加到類的實(shí)例對(duì)象屬性而不是原型對(duì)象屬性,如果組件被多次重用,每個(gè)實(shí)例都會(huì)有一個(gè)相同的函數(shù)實(shí)例,降低了函數(shù)實(shí)例的可重用性,造成了資源的浪費(fèi) Render(){ Return (<input type=“button” onClick={(e)=>{this.setNewState}/> ) } 3.Export default class a extends React.Component{ constructor(){ this.handleClick = this.handClick.bind(this)//構(gòu)造函數(shù)只執(zhí)行一次 } } handleClick(){xxxxx} <input type=“button” onClick={this.handleClick}/> //render方法每次執(zhí)行時(shí)都會(huì)調(diào)用bind方法生成新的函數(shù)實(shí)例 <input type=“button” onClick={this.handleClick.bind(this)}/>
15、避免使用內(nèi)聯(lián)樣式
使用內(nèi)聯(lián)樣式時(shí),會(huì)被編譯為JavaScript代碼,JavaScript將樣式規(guī)則映射到元素上,瀏覽器需要花費(fèi)更多時(shí)間處理腳本和渲染UI。
它是在執(zhí)行時(shí)為元素添加樣式,而不是在編譯時(shí)為元素添加樣式。
因此,性能非常的低,更好的辦法是將CSS文件導(dǎo)入組件。能通過(guò)css直接做的事情,就不要通過(guò)JavaScript去做,因?yàn)镴avaScript操作DOM非常慢
16、事件節(jié)流和防抖
利用debounce、throttle 避免重復(fù)回調(diào)
節(jié)流:
意味著不會(huì)立即執(zhí)行,在觸發(fā)事件之前會(huì)加上幾毫秒延遲,
throttle 更適合需要實(shí)時(shí)響應(yīng)用戶的場(chǎng)景中更適合,
如通過(guò)拖拽調(diào)整尺寸或通過(guò)拖拽進(jìn)行放大縮?。ㄈ纾簑indow 的 resize 事件)。實(shí)時(shí)響應(yīng)用戶操作場(chǎng)景中,如果回調(diào)耗時(shí)小,
甚至可以用 requestAnimationFrame 代替 throttle。
頁(yè)面滾動(dòng)到底部的時(shí)候,使用節(jié)流,否則觸發(fā)多個(gè)網(wǎng)絡(luò)請(qǐng)求調(diào)用,導(dǎo)致性能問(wèn)題
防抖:
在輸入框中鍵入數(shù)據(jù),直到用戶不再輸入數(shù)據(jù)為止,兼容網(wǎng)絡(luò)調(diào)用提升性能
在搜索場(chǎng)景中,只需響應(yīng)用戶最后一次輸入,無(wú)需響應(yīng)用戶的中間輸入值,
debounce 更適合使用在該場(chǎng)景中。
到此這篇關(guān)于React Native性能優(yōu)化紅寶書(shū)的文章就介紹到這了,更多相關(guān)React Native性能優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
30行代碼實(shí)現(xiàn)React雙向綁定hook的示例代碼
本文主要介紹了30行代碼實(shí)現(xiàn)React雙向綁定hook的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04Redis數(shù)據(jù)結(jié)構(gòu)面試高頻問(wèn)題解析
這篇文章主要為大家介紹了Redis數(shù)據(jù)結(jié)構(gòu)高頻面試問(wèn)題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06在React中實(shí)現(xiàn)分塊導(dǎo)出大量數(shù)據(jù)表格并壓縮成圖片的解決方案
在現(xiàn)代Web開(kāi)發(fā)中,處理和展示大量數(shù)據(jù)是一個(gè)常見(jiàn)的挑戰(zhàn),特別是在使用React框架時(shí),我們經(jīng)常需要將這些數(shù)據(jù)以表格的形式展示,并提供導(dǎo)出功能,本文將介紹如何在React中實(shí)現(xiàn)一個(gè)高效、分塊導(dǎo)出大量數(shù)據(jù)表格,并將其壓縮為圖片的解決方案,需要的朋友可以參考下2024-12-12ReactNative 之FlatList使用及踩坑封裝總結(jié)
本篇文章主要介紹了ReactNative 之FlatList使用及踩坑封裝總結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11解決react中useState狀態(tài)異步更新的問(wèn)題
本文主要介紹了react中useState狀態(tài)異步更新的問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07為什么說(shuō)form元素是React的未來(lái)
這篇文章主要介紹了為什么說(shuō)form元素是React的未來(lái),本文會(huì)帶你聊聊React圍繞form的布局與發(fā)展,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06