
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/,
] ,
} ) ;
} นำเข้ารหัสไฟล์ด้านบนลงในแอปรูท 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 ในตัวอย่างรหัสข้างต้น
'isequal
fromการปฏิบัติที่ดีที่สุดในการทำปฏิกิริยาที่ดีที่สุด' เพื่อเปรียบเทียบวัตถุด้วยความเท่าเทียมกันจริง แต่นั่นไม่ใช่ ความเท่าเทียมกันตื้น อีกต่อไป
หากคุณสร้างวัตถุในฟังก์ชั่นเรนเดอร์ของคุณพวกเขาจะถูกสร้างขึ้นใหม่ในการเรนเดอร์ทุกครั้ง ซึ่งหมายความว่าเมื่อคุณสร้างวัตถุในการเรนเดอร์แรกมันไม่ได้ อ้างอิง ถึงวัตถุในการเรนเดอร์ครั้งที่สอง ด้วยเหตุผลนี้มีการบันทึกความทรงจำ
useMemo hook เพื่อบันทึกอาร์เรย์และวัตถุซึ่งจะรักษาความเท่าเทียมกันอ้างอิง (และจะไม่ได้รับการสร้างขึ้นใหม่ในแต่ละการแสดงผล) ตราบใดที่การพึ่งพา (อาร์กิวเมนต์ที่สอง) ยังคงเหมือนเดิม ใช้ useMemo เพื่อแคชการคำนวณหนักเช่นการดำเนินการอาร์เรย์การกรอง ฯลฯuseCallback เพื่อบันทึกฟังก์ชั่นimport {useDeepEffect, ...} from 'react-native-best-practice' คุณสามารถใช้ useDeepEffect , useDeepCallback , useDeepImperativeHandle และ useDeepLayoutEffectโดยทั่วไปส่วนประกอบของฟังก์ชั่นสามารถปรับให้เหมาะสมได้ง่ายขึ้นเนื่องจากแนวคิดของตะขอ อย่างไรก็ตามคุณสามารถใช้เทคนิคที่คล้ายกันสำหรับส่วนประกอบคลาสเพียงโปรดทราบว่าสิ่งนี้จะส่งผลให้รหัสมากขึ้น
ในขณะที่แอนิเมชั่นและงานที่ใช้งานมากมีการกำหนดไว้ในเธรดเนทีฟลอจิกธุรกิจทั้งหมดของคุณทำงานบนเธรด 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 สิ่งเหล่านี้สามารถบันทึกได้ด้วย 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 ) ) ; Hook useState ยอมรับฟังก์ชั่น initializer ในขณะที่ตัวอย่างแรก ("ไม่ดี") เรียกใช้ .find การค้นหาในทุกการเรนเดอร์ตัวอย่างที่สองจะเรียกใช้ฟังก์ชันที่ผ่านเพียงครั้งเดียวเพื่อเริ่มต้นสถานะ
เมื่อเขียนส่วนประกอบใหม่ฉันมักจะใส่คำสั่งบันทึกไว้ในฟังก์ชั่นการแสดงผลของฉันเพื่อดูความถี่ที่ส่วนประกอบของฉันแสดงซ้ำในขณะที่ฉันกำลังทำงานอยู่ โดยทั่วไปส่วนประกอบควรแสดงผลอีกครั้งให้น้อยที่สุดและถ้าฉันเห็นบันทึกจำนวนมากที่ปรากฏในคอนโซลของฉันฉันรู้ว่าฉันทำอะไรผิด มันเป็นโรคระบาดที่ดีที่จะใส่ฟังก์ชั่นนี้ในส่วนประกอบของคุณเมื่อคุณเริ่มทำงานและลบออกเมื่อเสร็จแล้ว
function ComponentImWorkingOn ( ) {
// code
console . log ( 're-rendering ComponentImWorkingOn!' ) ;
return < View /> ;
}นอกจากนี้คุณยังสามารถใช้ไลบรารีทำไมต้อง-คุณเพื่อค้นหาว่า ทำไม ส่วนประกอบจึงแสดงผลอีกครั้ง (การเปลี่ยนแปลงข้อเสนอการเปลี่ยนแปลงของรัฐ ... ) และอาจจับข้อผิดพลาดได้ตั้งแต่เนิ่นๆ
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 และปลั๊กอิน 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 => จะโคลนวัตถุและอาร์เรย์อย่างลึกซึ้ง เปิดการตรวจสอบล่วงหน้าเสมอในขณะที่พัฒนาแอพเพราะมันจะบอกคุณว่า UI Framerate และ JS Framerate หากเฟรมใด ๆ ลดลงคุณสามารถตรวจสอบรหัสใหม่ที่ทำให้เฟรมลดลงและทำให้เวลาของคุณในการโต้ตอบ ( Show Perf Monitor ) ต่ำคุณสามารถเปิด Dev Menu ในแอปของคุณ 
อย่าใช้ลิสต์ Flatlist ใช้ Flashlist เสมอเพราะใช้แนวคิดของการรีไซเคิลมุมมองซึ่งสร้างและแสดงจำนวนมุมมองจำนวน จำกัด ที่มองเห็นได้บนหน้าจอ
สร้างอินสแตนซ์ Logger ที่กำหนดเองและบังคับใช้อีโมจิเพื่อจัดหมวดหมู่บันทึก วิธีนี้ง่ายกว่าที่จะพบสายที่เกี่ยวข้องในคอนโซลของคุณและดูเป็นมิตรโดยรวมมากขึ้น ทำการบันทึกจำนวนมากเพื่อช่วยตัวเองจากการดีบักคืนที่ยาวนานในภายหลัง! 
ใช้ Native-stack จาก @reactnavigation เสมอ เนื่องจากมันใช้หน้าจอดั้งเดิมของแพลตฟอร์มพื้นเมืองจึงคุ้มค่ากับประสิทธิภาพที่ได้รับจากสแต็กที่ใช้ JS 
Redux หากคุณใช้ Redux อยู่แล้วคุณควรใช้ Reselect สำหรับฟังก์ชั่น "ตัวเลือก" บันทึกความทรงจำ "
ทำปฏิกิริยาบริบท หากคุณใช้บริบท React อยู่แล้วคุณควรใช้การใช้บริบทการใช้งานเพื่อใช้สำหรับฟังก์ชั่น "ตัวเลือก" ที่บันทึกไว้มิฉะนั้นค่าบริบทจะเปลี่ยนไปส่วนประกอบทั้งหมดที่ USEcontext จะแสดงใหม่อีกครั้ง
แนะนำให้ใช้ libs recoil เหล่านี้ Jotai Zustand สำหรับการจัดการของรัฐ
หากคุณต้องการทำบางสิ่งบางอย่างในองค์ประกอบลูกจากองค์ประกอบหลักให้ใช้การอ้างอิงและใช้งาน imperativehandle สำหรับการโทรฟังก์ชั่นส่วนประกอบของเด็กจากองค์ประกอบหลักแทนที่จะเล่นกับสถานะที่ส่งผ่านส่วนประกอบเด็ก
ใช้ส้อม React-Native-Buffer จาก @craftzdog เมื่อต้องรับมือกับบัฟเฟอร์จำนวนมากเพื่อเร่งแอปของคุณ มันใช้การใช้งาน C ++ ที่ได้รับการสนับสนุนผ่าน JSI ซึ่งเร็วกว่าการใช้งานที่ใช้ JS ประมาณ 4x 
ใช้ React-Native-MMKV เพื่อจัดเก็บและดึงข้อมูลจากที่เก็บข้อมูลในท้องถิ่นซึ่งยังคงมีอยู่แม้ในการเปิดตัวแอปถัดไป เมื่อเปรียบเทียบกับ LocalStorage บนเว็บ MMKV ยังช่วยให้คุณเข้ารหัสข้อมูลของคุณและมีหลายอินสแตนซ์! 
ใช้ React-Native-Blurhash เพื่อแสดงตัวยึดที่เบลอที่สวยงามสำหรับรูปภาพและวิดีโอของคุณ สร้างสตริงสั้น ๆ ที่แสดงถึงเวอร์ชันที่เบลอของเนื้อหาของคุณ ("Blurhash") ฝั่งเซิร์ฟเวอร์และส่งไปพร้อมกับข้อมูลของคุณไปยังแอพ! 
เมื่อนำเสนอตัวเลขให้กับผู้ใช้คุณควรจัดรูปแบบในสถานที่ที่ถูกต้อง (เครื่องหมายจุลภาค, สัญญาณสกุลเงิน, .. ) ในขณะที่. tolocalestring (.. ) ทำงานได้จริงคุณสามารถสร้างอินสแตนซ์ NumberFormat ของคุณเองเพื่อปรับปรุงประสิทธิภาพโดย ~ 2X! 
จัดการกับพื้นที่ที่ปลอดภัยเสมอ แทนที่จะห่อหน้าจอทั้งหมดใน A คุณสามารถทำงานกับ Paddings เพื่อสร้าง UIs ที่สะอาดกว่า
ที่นี่เราผ่าน contentContainerStyle={{ paddingBottom: safeAreaBottom }} ไปที่:
อ่าน "C ++ ที่ทันสมัยที่มีประสิทธิภาพ" แม้ว่าคุณจะไม่ใช่นักพัฒนา C ++ หนังสือเล่มนี้จะช่วยให้คุณเข้าใจว่าการจัดการหน่วยความจำทำงานอย่างไรและเชื่อหรือไม่ว่าสิ่งนี้มีผลต่อวิธีที่คุณคิดเกี่ยวกับ React (Native) อันที่จริงนั่นเป็นหนังสือการเขียนโปรแกรมเล่มเดียวที่ฉันเคยอ่าน
คุณจะเข้าใจว่าทำไม {} === {} เป็นเท็จความเท่าเทียมกันของตัวตนทำงานได้อย่างไรการแสดงซ้ำเป็นจำนวนมากของการจัดสรรวิธีหลีกเลี่ยงสำเนาและสิ่งอื่น ๆ มากมายเกี่ยวกับประสิทธิภาพที่ทำให้คุณคิดว่าแตกต่างกันเล็กน้อยเมื่อเขียนโค้ด เพียงแค่ปรับให้เหมาะสมก่อนกำหนด?
และถ้าคุณต้องการเข้าสู่การพัฒนา C ++ กับ JSI มันจะดีกว่าที่คุณอ่านหนังสือเล่มนี้ - C ++ ไม่ได้ให้อภัยเหมือน JS หากคุณสร้างห้องสมุดที่มีรหัส C ++ ที่ไม่ดีผู้ใช้จะเกลียดคุณที่สร้างแอป Sigabrt ของพวกเขา?
อย่าใช้ส่วนประกอบโดยตรง ให้สร้างสิ่งที่เป็นนามธรรมของคุณเองเพื่อไม่ให้ตัวเองทำซ้ำด้วยชื่อตัวอักษรขนาดตัวอักษรหรือสีในแต่ละครั้งและง่ายต่อการเปลี่ยนคุณสมบัติ ณ จุดใด ๆ
นอกจากนี้ให้สร้างกฎ ESLINT เพื่อเตือนคุณทุกครั้งที่คุณพยายามใช้แทน️ 
เมื่อต้องรับมือกับตัวเลขจำนวนมากให้ใช้ react-native-bignumber แทนไลบรารีที่ใช้ JS ใด ๆ ⚡ได้รับการสนับสนุนโดยการใช้งาน C ++ บริสุทธิ์และเร็วกว่า BN.JS ~ 330X ในแอปพลิเคชันบางอย่าง (เช่น #Crypto Apps, ethers.js, รูปไข่, bitcoin) 
เมื่อทำงานกับ #Crypto / Cryptography ให้ใช้ React-Native-Quick-Crypto แทนที่จะเป็นห้องสมุดที่ใช้ JS ⚡ได้รับการสนับสนุนโดยการใช้งาน C ++ บริสุทธิ์และเร็วกว่า 58x มากกว่า React-Native-Crypto หรือ Crypto-Browserify ในบางสถานการณ์
คุณสามารถใช้ไฟฉายเพื่อสร้างคะแนนประสิทธิภาพสำหรับแอพ Android ของคุณ
คุณสามารถทำโปรไฟล์เพื่อเพิ่มประสิทธิภาพประสิทธิภาพ
คุณควรลบ console.log ออกจากแอพ PRED เป็นการใช้คำสั่ง console.log ช่วยลด FPS คุณสามารถลบ console.log ได้โดยการอ่านสิ่งนี้
ขอบคุณ Marc Rousavy และ Margelo เนื่องจากแนวทางปฏิบัติที่ดีที่สุดส่วนใหญ่เป็นของพวกเขา