
反应最佳实践是一种反应的最佳实践和一个包装,它为提高性能以及提高应用程序性能的实用程序提供了技术
您应该使用为什么会向您通知您有可能避免的重新订单的原因。
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),这主要是最好的做法