بهینه سازی برنامه های react native در سال 2021
در این مقاله روش های بهینه سازی سرعتبهینه سازی برنامه های react native را بررسی می کنیم. با ما همرا باشید.
عملکرد خوب برای هر برنامه یا محصولی بسیار مهم است. در حین کار با React Native، ممکن است اغلب با مشکلاتی در عملکرد برنامه خود مواجه شوید. به همین دلیل است که باید به بهترین شیوه ها و بهبود عملکرد برنامه React Native خود در طول توسعه آن توجه کنید تا بتوانید این مشکلات را برطرف کنید و تجربه ای بی عیب و نقص را به کاربران نهایی ارائه دهید.
بیایید به فهرستی از بهبودهای عملکرد و بهترین شیوههایی که میتوانید در هنگام توسعه برنامههای React Native از آنها استفاده کنید، عمیقاً بپردازیم!
ارائه استراتژی های ناوبری مناسب Provide Appropriate Navigation Strategies
تیم React Native مدت زیادی است که روی رفع مشکلات مربوط به ناوبری کار کرده است و بسیاری از آنها را برطرف کرده است، اما هنوز هم برخی از مشکلات وجود دارد که برای اکثر برنامهها باید برطرف شود تا تجربهای بینظیر ارائه دهند.
پیمایش دشوار بین صفحهها میتواند مانع از استفاده کاربران از برنامه شما شود. React Native چهار راه مختلف برای ساخت ناوبری ارائه می دهد:
- iOS Navigator : فقط برای iOS قابل استفاده است و در توسعه ناوبری اندروید کمکی نمی کند.
- Navigator : فقط برای برنامه های کوچک و توسعه نمونه اولیه قابل استفاده است. برای برنامه های پیچیده یا با کارایی بالا خوب کار نمی کند.
- Navigation Experiment : می تواند در برنامه های پیچیده استفاده شود، اما به دلیل پیچیدگی اجرای آن، همه آن را دوست ندارند.
- React Navigation: توسط تعداد زیادی برنامه استفاده می شود و اغلب توصیه می شود. React Navigation سبک وزن است و می تواند برای برنامه های کوچک و بزرگ کار کند.
در لیست های بزرگ از ScrollView استفاده نکنید!
چند راه برای نمایش موارد با لیست های قابل پیمایش در React Native وجود دارد. دو روش رایج برای پیاده سازی لیست ها در React Native از طریق استفاده از مولفه های ScrollView و FlatList است.
پیاده سازی ScrollView ساده است. همانطور که در زیر نشان داده شده است اغلب برای تکرار بر روی لیستی از تعداد محدودی از موارد استفاده می شود. با این حال، همه کودکان را به یکباره رندر می کند. این رویکرد زمانی خوب است که تعداد موارد موجود در لیست بسیار کم باشد. از سوی دیگر، استفاده از ScrollView با حجم زیاد داده می تواند به طور مستقیم بر عملکرد کلی برنامه React Native تأثیر بگذارد.
<ScrollView> {items.map(item => { return <Item key={item.name.toString()} />; })} </ScrollView>
برای مدیریت حجم زیادی از داده ها در قالب لیست، React Native FlatList را ارائه می دهد. موارد موجود در FlatList تنبل بارگذاری می شوند. از این رو، برنامه از مقدار بیش از حد یا متناقض حافظه استفاده می کند. FlatList را می توان مطابق شکل زیر استفاده کرد:
<FlatList data={elements} keyExtractor={item => `${items.name}`} renderItem={({ item }) => <Item key={item.name.toString()} />} />
از ارسال توابع درون خطی به عنوان Props خودداری کنید
هنگام ارسال یک تابع به عنوان یک ویژگی به یک جزء، از انتقال آن تابع به صورت درون خطی مانند زیر اجتناب کنید:
function MakeBeverage(props) { return( <Button title=' Make Beverage' onPress={props.onPress}/> ) } export default function BeverageMaker() { return ( <View style={styles.container}> <MakeBeverage onPress={()=> console.log('making some beverage')} /> </View> ); }
روش فوق توصیه نمی شود زیرا هر زمان که والد یک مرجع جدید را مجدداً ارائه کند، تابع دوباره ایجاد می شود. این به این معنی است که مولفه فرزند حتی زمانی که پایه ها اصلاً تغییر نکرده اند دوباره رندر می شود.
راه حل این است که تابع را به عنوان یک متد کلاس یا به عنوان یک تابع در داخل یک مؤلفه تابعی اعلام کنیم تا مراجع هرگونه امکان رندرهای مجدد را از بین ببرند.
export default function BeverageMaker() { function handleMakeBeverage(){ console.log('Making beverage, please wait!') } return ( <View style={styles.container}> <MakeBeverage onPress={handleMakeBeverage} /> </View> ); }
مقیاس و تغییر اندازه تصاویر Scale and Resize Images
اگر برنامه برای نمایش حجم عظیمی از محتوای گرافیکی یا تصاویر ساخته شده باشد، بهینه سازی تصاویر برای بهبود عملکرد برنامه React Native بسیار مهم است. در صورتی که تصاویر از نظر وضوح و اندازه بهینه سازی نشده باشند، رندر کردن چندین تصویر می تواند منجر به مصرف بالای حافظه در دستگاه شود. این ممکن است باعث از کار افتادن برنامه شما به دلیل اضافه بار حافظه شود.
برخی از پیشرفت هایی که می توان برای بهینه سازی تصاویر در برنامه React Native اعمال کرد عبارتند از:
- استفاده از فرمت PNG به جای فرمت JPG
- استفاده از تصاویر با وضوح کمتر
- استفاده از فرمت WEBP برای تصاویر – این می تواند به کاهش اندازه باینری تصاویر در iOS و Android تقریباً یک سوم اندازه اصلی کمک کند!
کش تصاویر Cache Images
React Native تصاویر را به عنوان یک مؤلفه اصلی ارائه می دهد. این کامپوننت برای نمایش تصویر استفاده می شود، اما راه حلی خارج از جعبه برای مسائلی مانند موارد زیر ندارد:
- رندر کردن تعداد زیادی عکس روی یک صفحه
- عملکرد پایین به طور کلی
- عملکرد پایین در بارگذاری کش
- سوسو زدن تصویر
با این حال، این مسائل را می توان به راحتی با استفاده از کتابخانه های شخص ثالث، مانند react-native-fast-image . این کتابخانه هم برای iOS و هم برای اندروید در دسترس است و مانند یک جادو عمل می کند!
اجتناب از به روز رسانی state
یا dispatch
اقدامات در componentWillUpdate
شما باید از روش چرخه حیات componentWillUpdate برای آماده شدن برای به روز رسانی استفاده کنید، نه برای راه اندازی یکی دیگر. اگر هدف شما تنظیم یک حالت است، باید این کار را با استفاده از componentWillReceiveProps انجام دهید. برای ایمن بودن، از componentDidUpdate به جای componentWillReceiveProps برای ارسال هر اقدام Redux استفاده کنید.
از رندر اضافه و رندرهای غیر ضروری خودداری کنید
React Native رندر کامپوننت ها را به روشی مشابه React.js انجام می دهد. بنابراین، تکنیکهای بهینهسازی که برای React معتبر هستند، برای برنامههای React Native نیز اعمال میشوند. یکی از تکنیکهای بهینهسازی، اجتناب از رندرهای غیرضروری در موضوع اصلی است. در کامپوننت های کاربردی، این کار را می توان با استفاده از React.memo انجام داد.
React.memo برای مدیریت حافظهگذاری استفاده میشود، به این معنی که اگر هر مؤلفه مجموعهای از ویژگیهای یکسان را بیش از یک بار دریافت کند، از ویژگیهای ذخیرهشده قبلی استفاده میکند و نمای JSX را که توسط مؤلفه عملکردی برگردانده شده است تنها یک بار ارائه میکند و در سربار رندر صرفهجویی میکند.
یک مثال خوب از این در زیر نشان داده شده است، جایی که مولفه Animal دارای یک متغیر حالت به نام leg count است که هر زمان که دکمه فشار داده می شود با یک عدد مرتبط با هر جفت به روز می شود. هنگامی که دکمه فشار داده می شود، مولفه WildAnimal دوباره رندر می شود، حتی اگر ویژگی متن آن با هر رندر تغییر نمی کند. کار خاصی برای مولفه Animal والد خود انجام نمی دهد و فقط متن را نمایش می دهد. این را می توان با بسته بندی محتویات جزء WildAnimal با React.memo بهینه کرد.
// Animal.js const Animal = () => { const [count, setCount] = useState(0); return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Button title='Press me' onPress={() => setCount(count + 2)} /> <WildAnimal text='text' /> </View> ); }; // WildAnimals.js const WildAnimal = React.Memo(({ text }) => { return <Text>{text}</Text>; });
از هرمس استفاده کنید Hermes
hermes یک موتور جاوا اسکریپت منبع باز است که به طور خاص برای برنامه های تلفن همراه بهینه شده است. برای پلتفرم اندروید برای React Native نسخه 0.60.4 و بالاتر در دسترس است. همچنین برای iOS از نسخه 0.64-rc.0 و بالاتر در دسترس است. هرمس به کاهش اندازه دانلود APK، ردپای حافظه و مصرف، و زمان مورد نیاز برای تعاملی شدن برنامه کمک می کند (TTI – Time to Interact).
برای فعال کردن هرمس برای اندروید، build.gradle را باز کنید و خط زیر را اضافه کنید:
def enableHermes = project.ext.react.get("enableHermes", true);
برای فعال کردن هرمس برای iOS، Podfile را باز کنید و خط زیر را اضافه کنید:
use_react_native!(:path => config[:reactNativePath], :hermes_enabled => true
از nativeDriver با کتابخانه متحرک استفاده کنید
یکی از محبوب ترین روش های رندر انیمیشن در برنامه های React Native استفاده از کتابخانه animated است.
این برنامه از nativeDriver برای ارسال انیمیشن ها بر روی پل اصلی قبل از شروع انیمیشن روی صفحه استفاده می کند. این کمک میکند انیمیشنها مستقل از رشتههای مسدود شده جاوا اسکریپت اجرا شوند، بنابراین تجربهای روانتر و غنیتر را بدون سوسو زدن یا رها کردن فریمهای زیاد ایجاد میکنند. برای استفاده از nativeDriver با Animated، میتوانید مقدار آن را مطابق شکل زیر روی true تنظیم کنید:
<ScrollView showsVerticalScrollIndicator={ false } scrollEventThrottle={ 1 } onScroll={Animated.event( [{ nativeEvent: { contentOffset: { y: animatedValue } } }], { useNativeDriver: false } )} > </ScrollView>
از arrow function استفاده نکنید!
توابع پیکان (arrow function) یک مقصر رایج برای رندرهای مجدد بیهوده هستند. از توابع پیکان به عنوان پاسخ تماس در توابع خود برای نمایش نماها استفاده نکنید. با تابع فلش، هر رندر یک نمونه جدید از آن تابع خاص تولید می کند، بنابراین زمانی که اصلاح می شود ، React Native یک تفاوت را مقایسه می کند و چون مرجع تابع مطابقت ندارد، نمی تواند از مراجع قدیمی استفاده مجدد کند.
class ArrowClass extends React.Component { // ... addTodo() { // ... } render() { return ( <View> <TouchableHighlight onPress={() => this.addTodo()} /> </View> ); } } class CorrectClass extends React.Component { // ... addTodo = () => { // ... } render() { return ( <View> <TouchableHighlight onPress={this.addTodo} /> </View> ); } }
از استفاده بیش از حد از قطعات درجه بالاتر خودداری کنید
هنگامی که برنامه شما پیچیده می شود و می خواهید الگوهای مشترکی را در بین اجزای خود به اشتراک بگذارید، استفاده از اجزای مرتبه بالاتر معمول است. استفاده از مولفه های مرتبه بالاتر، در واقع، عمل خوبی است، حتی اگر گاهی اوقات قابل بحث باشد، زیرا غیر جهت را افزایش می دهد. با این حال، می تواند پیچیدگی کد شما را افزایش دهد.
چیزی که واقعاً باید مراقب آن باشید این است که یک جزء با مرتبه بالاتر را به طور خاص در طول یک روش رندر نمونه سازی نکنید. این به این دلیل است که این الگو به طور موثر اجزای جدیدی را به تنهایی ایجاد می کند.
React Native نمیداند (و شناسایی نمیکند) که این مؤلفه عملاً همان مؤلفه قبلی است. این فشار زیادی را بر الگوریتم های آشتی وارد می کند. بیشتر از آن، React Native را نیز مجبور میکند تا تمام روشهای چرخه حیات را اجرا کند.
از اجرای کاهنده های انبوه خودداری کنید Avoid Implementing Bulk Reducers
اگر از Redux با normalizr و یا rematch استفاده نمیکنید یا خودتان در حال نوشتن کاهشدهندهها هستید، مراقب باشید همیشه فقط اشیایی را که نیاز دارید تغییر دهید. هنگام واکشی مجدد لیستی از آیتم ها از شبکه و ذخیره آن در کاهش دهنده، رویکرد ساده لوحانه به این صورت به نظر می رسد:
function customReducer (state = {}, action) { switch (action.type) { case UPDATE_ITEMS_DOCS: return { ...state, ...action.docs } } } return state }
کاری که واقعاً باید انجام دهید این است که فروشگاه خود را فقط در صورت نیاز به روز کنید. به طور دقیق تر، فقط مراجعی را به روز کنید که باید به روز شوند. اگر یک مورد از قبل همان مقدار قبلی را دارد، دیگر نیازی به ذخیره یک مرجع جدید برای آن در Redux ندارید. به روز رسانی مراجع در فروشگاه شما رندرهای بی فایده ای ایجاد می کند که بارها و بارها همان اجزا را تولید می کنند.
نماها را با احتیاط جابه جا کنید Move Views With Caution
جابجایی نماها روی صفحه با پیمایش، ترجمه و چرخش، FPS رشته رابط کاربری را کاهش میدهد. این امر مخصوصاً زمانی صادق است که متنی با پسزمینه شفاف در بالای تصویر قرار دهید یا در هر موقعیت دیگری که از ترکیب آلفا برای ترسیم مجدد نماها در هر فریم استفاده میشود. متوجه خواهید شد که فعال کردن shouldRasterizeIOS یا renderToHardwareTextureAndroid می تواند به بهبود عملکرد به طور قابل توجهی کمک کند.
مراقب باشید که از آن بیش از حد استفاده نکنید، زیرا ممکن است میزان استفاده از حافظه شما به طور تصاعدی بیشتر شود. هنگام استفاده از این ویژگیها، عملکرد و میزان مصرف حافظه خود را مشخص کنید. اگر دیگر قصد ندارید هیچ نمائی را جابجا کنید، این ویژگی را خاموش کنید.
از منابع سبک به درستی استفاده کنید Use Style References Correctly
اگر از اشیاء یا آرایهها برای استایلسازی استفاده میکنید، با هر رندر جدید نمونههای جدیدی ایجاد میکنند. شما باید از یک StyleSheet در React Native استفاده کنید، که همیشه به جای ایجاد و تخصیص یک شیء یا آرایه جدید، یک مرجع ارسال می کند.
class StylingClass extends React.PureComponent { render() { const style = {width: 10, height: 10} return ( <View style={{flex: 1}}> <View style={[style, {backgroundColor: 'red'}]}/> </View> ); } } import {StyleSheet} from 'react-native'; class CorrectClass extends React.PureComponent { render() { return ( <View style={style.container}/> ); } } StyleSheet.create({ container: { flex: 1 } });
از InteractionManager استفاده کنید
InteractionManager به شما این امکان را می دهد تا پس از اتمام هر گونه تعامل یا انیمیشن، اجرای وظایف در رشته جاوا اسکریپت را برنامه ریزی کنید. به طور خاص، InteractionManager به انیمیشنهای جاوا اسکریپت اجازه میدهد تا به راحتی اجرا شوند.
می توان با استفاده از کد زیر، وظایف را برای اجرا پس از تعامل برنامه ریزی کرد:
InteractionManager.runAfterInteractions(() => { // ...long-running synchronous task... });
از توابع ناشناس هنگام رندر اجتناب کنید
ایجاد توابع در رندر یک عمل بد است که می تواند منجر به برخی مشکلات جدی عملکرد شود. هر بار که یک کامپوننت دوباره ارائه می شود، یک فراخوان متفاوت ایجاد می شود. این ممکن است برای کامپوننتهای ساده و کوچکتر مشکلی نداشته باشد، اما برای PureComponents و React.memo یا زمانی که این تابع بهعنوان پایه به یک مؤلفه فرزند ارسال میشود، مشکل بزرگی است که منجر به رندرهای غیرضروری میشود.
بیانیه های کنسول را حذف کنید
استفاده از دستورات console.log یکی از رایج ترین الگوها برای اشکال زدایی در برنامه های جاوا اسکریپت به طور کلی، از جمله برنامه های React Native است. گذاشتن دستورات کنسول در کد منبع هنگام انتشار برنامههای React Native میتواند باعث ایجاد گلوگاههای بزرگ در رشته جاوا اسکریپت شود.
یکی از راههای پیگیری خودکار عبارات کنسول و حذف آنها، استفاده از وابستگی شخص ثالث به نام babel-plugin-transform-remove-console است. با اجرای دستور زیر در پنجره ترمینال می توانید وابستگی را نصب کنید:
npm install babel-plugin-transform-remove-console # OR yarn add babel-plugin-transform-remove-console
پس از نصب، فایل .babelrc را تغییر دهید تا عبارات کنسول حذف شوند، مانند شکل زیر:
{ "env": { "production": { "plugins": ["transform-remove-console"] } } }
فرمت RAM را فعال کنید
با استفاده از فرمت رم در iOS یک فایل ایندکس شده ایجاد می شود که React Native هر بار یک ماژول را بارگذاری می کند. در اندروید، به طور پیش فرض مجموعه ای از فایل ها را برای هر ماژول ایجاد می کند. میتوانید اندروید را مجبور کنید که یک فایل ایجاد کند، مانند iOS، اما استفاده از چندین فایل میتواند کارایی بیشتری داشته باشد و به حافظه کمتری در اندروید نیاز دارد.
با ویرایش مرحله ساخت «Bundle React Native code and images»، فرمت RAM را در Xcode فعال کنید. قبل از
../node_modules/react-native/scripts/react-native-xcode.sh صادرات را اضافه کنید BUNDLE_COMMAND = “ram-bundle”
export BUNDLE_COMMAND="ram-bundle" export NODE_BINARY=node ../node_modules/react-native/scripts/react-native-xcode.sh
در Android، با ویرایش فایل Android / app / build.gradle، فرمت RAM را فعال کنید. قبل از اعمال خط از: “../../node_modules/react-native/react.gradle”، بلوک project.ext.react را اضافه یا تغییر دهید:
project.ext.react = [ bundleCommand: "ram-bundle", ]
اگر می خواهید از یک فایل ایندکس شده استفاده کنید، از خطوط زیر در اندروید استفاده کنید:
project.ext.react = [ bundleCommand: "ram-bundle", extraPackagerArgs: ["--indexed-ram-bundle"] ]
توجه: اگر از موتور هرمس JS استفاده می کنید، به بسته های رم نیاز ندارید. هنگام بارگذاری بایت کد، mmap اطمینان حاصل می کند که کل فایل بارگیری نمی شود.
از بهینه سازی حافظه استفاده کنید
برنامه های بومی دارای پردازش های زیادی در پس زمینه هستند. برای بهبود عملکرد می توانید موارد غیر ضروری را با کمک Xcode پیدا کنید. در اندروید استودیو یک مانیتور دستگاه اندروید وجود دارد که برای نظارت بر نشت در برنامه ها استفاده می شود. استفاده از لیست های پیمایشی مانند FlatListSectionList یا isVirtualList راهی مطمئن برای افزایش عملکرد است.
برای نظارت بر عملکرد و شناسایی نشت حافظه می توانید از کد زیر استفاده کنید:
Import PerfMonitor from 'react-native/libraries/Performance/RCTRenderingPerf'; perfMonitor.toggle(); PerfMonitor.start(); SetTimeout ( () => { perfMonitor.stop(); }; 2000); }; 5000);
از ورودی های کنترل نشده استفاده کنید
برخلاف بهترین روش ها در React، که در آن بیشتر فیلدهای ورودی ورودی های کنترل شده هستند، استفاده از ورودی های کنترل نشده در React Native کارایی بیشتری دارد.
مشکل ورودیهای کنترلشده در React Native این است که در دستگاههای کندتر یا زمانی که کاربر واقعاً سریع تایپ میکند، ممکن است هنگام بهروزرسانی نما، اشکالات رندر رخ دهد. ورودیهای کنترلشده باید از RN-bridge عبور کنند، زیرا هم با موضوع اصلی و هم با رشته جاوا اسکریپت سروکار دارد.
با توجه به محدودیت های عملکرد شناخته شده پل RN، استفاده از ورودی های کنترل نشده در دسترس ترین رویکرد است. این کار به سادگی حذف ویژگی ارزش است. همچنین، مجبور نیستید با رندرهای مجدد سر و کار داشته باشید زیرا وقتی ورودی های کنترل نشده اصلاح می شوند، هیچ تغییر حالتی ایجاد نمی شود.
export default function UncontrolledInputs() { const [text, onTextChange] = React.useState('Controlled inputs'); return ( <TextInput style={{ borderWidth: 1, height: 100, borderColor: 'blue' }} onChangeText={text => onTextChange(text)} defaultValue={text} /> ); }
سایز برنامه اندروید را بهینه کنید
در ابتدای هر پروژه React Native، معمولاً به اندازه برنامه اهمیتی نمی دهید. به هر حال، انجام چنین پیشبینیهایی در مراحل اولیه کار دشواری است. اما تنها چند وابستگی اضافی لازم است تا برنامه از 5 مگابایت استاندارد به 10، 20 یا حتی 50 برسد، بسته به پایگاه کد.
به طور پیش فرض، یک برنامه React Native در اندروید شامل موارد زیر است:
- چهار مجموعه باینری برای معماران CPU مختلف کامپایل شده است
- دایرکتوری با منابعی مانند تصاویر، فونت ها و غیره.
- یک بسته جاوا اسکریپت با منطق تجاری و اجزای React شما
- فایل های دیگر
فلگ بولین enableProguardInReleaseBuilds را روی true تنظیم کنید، قوانین ProGuard را با نیازهای خود تنظیم کنید و نسخههای انتشار را برای خرابی آزمایش کنید.
همچنین enableSeparateBuildPerCPUArchitecture را روی true قرار دهید.
همچنین باید با استفاده از مزیت Android App Bundles هنگام انتشار نسخه تولیدی برنامه خود، فرآیند توزیع را بهینه کنید.
اشکال زدایی سریعتر با Flipper
اشکال زدایی یکی از چالش برانگیزترین وظایف هر توسعه دهنده ای است. هنگامی که به نظر می رسد همه چیز کار می کند، معرفی یک ویژگی جدید آسان تر است، اما پیدا کردن آنچه اشتباه شده می تواند بسیار خسته کننده باشد.
زمان عامل مهمی در فرآیند اشکال زدایی است و معمولاً باید مسائل را به سرعت حل کنیم. با این حال، اشکال زدایی در React Native خیلی ساده نیست، زیرا مشکلی که شما سعی در حل آن دارید می تواند در سطوح مختلف رخ دهد. یعنی ممکن است ناشی از:
- جاوا اسکریپت: کد برنامه شما یا React Native
- کد نیتیو: کتابخانه های شخص ثالث یا خود React Native
فلیپر یک پلت فرم اشکال زدایی برای برنامه های موبایل است. همچنین پشتیبانی گسترده ای از React Native دارد.
از نظارت بر عملکرد Firebase استفاده کنید
نظارت بر عملکرد Firebase سرویسی است که توسط Google ارائه میشود و به شما کمک میکند تا در مورد ویژگیهای عملکرد برنامه خود اطلاعاتی کسب کنید. firebase performance monitoring sdk باید از React Native برای جمعآوری آمار عملکرد و دادهها از برنامههای خود استفاده کنید، سپس آن دادهها را در کنسول Firebase بررسی و تجزیه و تحلیل کنید.
نتیجه
ریاکت نیتیو یک چارچوب متن باز برای ایجاد برنامه های کاربردی تلفن همراه چند پلتفرمی است. جاوا اسکریپت در هسته آن قرار دارد و دارای اجزایی برای ساخت رابط ها و عملکردها است. این یک چارچوب محبوب با عملکرد بالا است که تا زمانی که از همان ابتدا برنامههایی را با عملکرد در ذهن خود بسازید، یک تجربه یکپارچه را در مقیاس ارائه میکند.
به نظر شما ریاکت نیتیو یا فلاتر ؟