ده روش برای بهبود کارایی اپلیکیشن های ری اکت [ReactJS App]
![ده روش برای بهبود کارایی اپلیکیشن های ری اکت [ReactJS App]](https://rahkarino.ir/wp-content/uploads/2021/03/reactjs-app.jpg)
بهینه بودن یکی از مهم ترین معیارهایی است که هنگام توسعه هر نرم افزار به ویژه وب اپلیکیشن باید در نظر داشت. فریم ورک ها و کتابخانه های جاوا اسکریپتی مانند ReactJS و Angular ویژگی ها و تنظیماتی برای بهینه سازی اپلیکیشن ها در اختیار توسعه دهندگان قرار می دهند. در این پست می خواهیم ترفندهایی را معرفی کنیم که بتوانید وب اپلیکیشن های ریکتی را بهینه کنید و کارایی آنها را افزایش دهید.
در توسعه اپلیکیشن با react باید سعی شود اصول کدنویسی تمیز رعایت شود.
پیشنهاد راهکارینو: مطالعه مقاله “قواعد کدنویسی تمیز” توصیه می شود.
همچنین باید کامپوننت ها را به نحوی بنویسید که بتوانید از آن در سایر پروژه ها نیز استفاده کنید. در واقع قابل استفاده مجدد یا reusable باشد.
اگر در حین توسعه اپلیکیشن و کدنویسی آن زمان زیادی را صرف کد زدن تمیز به همراه کامنت های توصیفی کنید بهتر است. زیرا در آینده توسعه و نگهداری آن ساده تر خواهد بود و با خطاهای کمتری مواجه خواهید شد.
روش های بهینه سازی کارایی و سرعت اپلیکیشن های ری اکت:
در ادامه می خواهیم 10 ترفند کاربردی را برای افزایش بهره وری و performance اپلیکیشن های ریکتی معرفی کنیم:
1- ()useMemo:
UseMemo یکی از هوک های ریکت (React Hook) می باشد که برای کار با کش (cache) در اپلیکیشن های ری اکت بکار می رود.
بیایید نگاهی به مثال زیر بیاندازیم:
function App() { const [count, setCount] = useState(0) const expFunc = (count)=> { waitSync(3000); return count * 90; } const resCount = expFunc(count) return ( <> Count: {resCount} <input type="text" onChange={(e)=> setCount(e.target.value)} placeholder="Set Count" /> </> ) }
در کد بالا یک فانکشن سنگین داریم بنام expFunc که اجرای آن 3 ثانیه زمان می برد! در واقع قبل از اینکه آرگومان ورودی count را در عدد 90 ضرب کند 3 ثانیه منتظر می ماند.
در ادامه کد یک متغیر داریم بنام resCount که تابع expFunc را با متغیر count که از هوک state گرفتیم فراخوانی می کند. پس یک input داریم که با هر بار تایپ در آن، count state آپدیت می شود.
هر بار که کاربر در input تایپ می کند باعث می شود app یکبار re-render شود و هر بار تابع expFunc صدا زده شود. پس در اینحالت با هر تغییر در مقدار input تابع مذکور فراخوانی شده و باعث می شود 3 ثانیه طول می کشد تا اپلیکیشن مجددا رندر شود. پس performance برنامه بسیار پایین خواهد بود.
در صورتیکه روش صحیح اینست که با هر بار تغییر input تابع expFunc اجرا نشود و باید مقدار input را در جایی ذخیره کنیم. برای رفع این مشکل می توانیم از هوک useMemo استفاده کنیم. ساختار این هوک بصورت زیر است:
useMemo(()=> func, [input_dependency])
func فانکشنی است که می خواهیم کش cache شود. آرایه input_dependency هم برابر آرایه ای از input ها می باشد که useMemo از آنها استفاده می کند. اگر مقدار این input ها تغییر یابد تابع func فراخوانی می شود.
اکنون در فانکشنال کامپوننت زیر از هوک useMemo استفاده خواهیم کرد:
function App() { const [count, setCount] = useState(0) const expFunc = (count)=> { waitSync(3000); return count * 90; } const resCount = useMemo(()=> { return expFunc(count) }, [count]) return ( <> Count: {resCount} <input type="text" onChange={(e)=> setCount(e.target.value)} placeholder="Set Count" /> </> ) }
در این حالت، نتایج تابع expFunc کش می شود. یعنی هوک useMemo بررسی می کند که اگر مقدار input یکسان بود و تغییر نکرد تابع expFunc را فراخوانی نمی کند و باعث افزایش بهره وری کامپوننت خواهد شد.
بنابراین برای افزایش سرعت اجرای اپلیکیشن و بهبود کارایی آن می توانید از تکنیک کش useMemo استفاده کرد. علاوه بر این می توان از این قابلیت برای props در کامپوننت های تابعی استفاده کرد.
2- نمایش لیست طولانی:
اگر می خواهید یک لیست طولانی و داده زیاد را در اپلیکیشن خود رندر کنید، توصیه می شود دیتا را بخش بندی کنید و در هر viewport کاربر، قسمتی از لیست را به او نمایش دهیم. و تمام لیست را یکدفعه در لود اولیه نمایش ندهیم. برای مشاهده ادامه لیست می توان با اسکرول کاربر اینکار را انجام دهیم یا اینکه صفحه بندی یا pagination پیاده سازی شود. در ریکت، کتابخانه های زیادی وجود دارد که می توان این سناریو را مدیریت کرد. دو نمونه از آنها react-window و react-virtualized هستند که توسط آقای Brian Vaughn توسعه داده شده اند.
برای نصب لایبرری react-window کافیست دستور زیر را توسط npm اجرا کنیم:
npm install --save react-window
و برای نصب لایبرری react- virtualized باید دستور زیر را توسط npm اجرا کنیم:
npm install react-virtualized --save
3- React.PureComponent
درست مانند کاری که متد shouldComponentUpdate در کلاس کامپوننت انجام می دهد، React.PureComponent نیز همینکار را می کند.
React.PureComponent یک کلاس کامپوننت base ات که تمام فیلدهای state و props را چک می کند و در صورتی که تغییر پیدا کنند کامپوننت آپدیت خواهد شد. در غیر اینصورت رندر نخواهد شد.
بیایید کامپوننت فوق را با متد shouldComponentUpdate پیاده سازی کنیم:
class ReactComponent extends Component { constructor(props, context) { super(props, context) this.state = { data: null } this.inputValue = null } handleClick = () => { this.setState({data: this.inputValue}) } onChange = (evt) => { this.inputValue = evt.target.value } shouldComponentUpdate( nextProps,nextState) { if(nextState.data === this.state.data) return false return true } render() { l("rendering App") return ( <div> {this.state.data} <input onChange={this.onChange} /> <button onClick={this.handleClick}>Click Me </button> </div> ) } }
و در قطعه کد زیر از React.PureComponent استفاده کرده ایم:
class ReactComponent extends React.PureComponent { constructor(props, context) { super(props, context) this.state = { data: null } this.inputValue = null } handleClick = () => { this.setState({data: this.inputValue}) } onChange = (evt) => { this.inputValue = evt.target.value } render() { l("rendering App") return ( <div> {this.state.data} <input onChange={this.onChange} /> <button onClick={this.handleClick}>Click Me </button> </div> ) } }
همانطور که در کد فوق مشاهده می کنید React.PureComponent را جایگزین متد shouldComponentUpdate کرده ایم. اگر فرضا عدد 2 را در input تایپ کنیم و دکمه را بزنیم ReactComponent تنها یکبار اجرا می شود و دیگر اجرا نمی شود. زیرا تغییری در input نداریم.
نحوه کار React.PureComponent به اینصورت است که مقدار state و props قبل را مقدار بعدی آنها مقایسه می کند. اگر تغییری داشتند کامپوننت re-render می شود. بنابراین React.PureComponent با بهینه کردن تعداد رندرهای کامپوننت، باعث افزایش کارایی برنامه خواهد شد.
4- توابع کش یا caching functions:
در کامپوننت های ریکت، توابع می توانند در JSX بصورت زیر صدا زده شوند:
function expensiveFunc(input) { ... return output }class ReactCompo extends Component { render() { return ( <div> {expensiveFunc} </div> ) } }
در اینحالت اگر اجرای تابع expensiveFunc زمانبر باشد، باعث می شود رندر شدن ادامه کدها معطل بماند و در نهایت منجر به تجربه کاربری یا UX ضعیف شود.
همانطور که کامپوننت ReactCompo را در مثال بالا مشاهده می کنید، در JSX رندر می شود و در هر بار re-render شدن تابع expensiveFunc فراخوانی می شود و مقدار بازگشتی در DOM نمایش می یابد. پس در هر بار رندر کامپوننت باید منتظر تمام شدن اجرای expensiveFunc باشیم و رندر ادامه کدهای JSX با اختلال و تاخیر مواجه می شود.
بهترین راه برای رفع این مشکل کش کردن تابع expensiveFunc است. در اینصورت ادامه کد رندر می شود و معطل اجرای تابع expensiveFunc نمی ماند.
کد زیر را در نظر بگیرید:
function expensiveFunc(input) { ... return output }const memoizedExpensiveFunc = memoize(expensiveFunc)class ReactCompo extends Component { render() { return ( <div> {memoizedExpensiveFunc} </div> ) } }
5- استفاده از سلکتورهای reselect:
توسط reselect می توان ریداکس (state management) را بهینه سازی کرد.
همانطور که احتمالا می دانید ریداکس به شکل immutable کار می کند. به این معنی که با هر بار dispatch شدن action رفرنس های جدیدی از آبجکت تعریف می شود. این قضیه باعث کاهش بهره وری و کارایی نرم افزار خواهد شد. زیرا حتی اگر رفرنس آبجکت تغییر کند، کامپوننت re-render می شود. با اینکه فیلدهای آبجکت تغییر نکرده اند.
لایبرری Reselect state ریداکس را کپسوله سازی یا encapsulate می کند و چک خواهد کرد که هر زمان مقدار فیلدهای آبجکت state تغییر کرد کامپوننت مجددا رندر شود.
بنابراین reselect باعث می شود در زمان اجرای اپلیکیشن صرفه جویی شود. به این صورت که مقدار state قبل و بعد را چک می کند و اگر تغییر پیدا کرده بود کامپوننت re-render خواهد شد. وگرنه با تغییر رفرنس آبجکت state کامپوننت رندر نخواهد شد.
6- Web Worker:
کدهای جاوا اسکریپت روی یک single thread اجرا می شوند. از طرفی اجرای یک تسک زمانبر روی یک thread واحد می تواند بشدت رندر UI را تحت تاثیر قرار دهد. پس بهترین روش اینست که این تسک روی یک Thread دیگر اجرا شود.
اینکار توسط Web worker ها انجام می شود.
web worker ها با ایجاد gateway این امکان را به ما می دهند که thread جدید تعریف کنیم و تسک موردنظر خود را روی آن و بطور موازی با main thread اجرا کنیم. در اینحالت مشکل رندر UI هم نخواهیم داشت.
ما می توانیم از Web worker در ریکت استفاده کنیم. اگرچه کتابخانه ReactJS بطور رسمی از Web worker ها پشتیبانی نمی کند. اما روش هایی وجود دارد که می توانیم web worker را به اپلیکیشن ریکتی خود اضافه کنیم. بعنوان مثال:
// webWorker.js const worker = (self) => { function generateBigArray() { let arr = [] arr.length = 1000000 for (let i = 0; i < arr.length; i++) arr[i] = i return arr } function sum(arr) { return arr.reduce((e, prev) => e + prev, 0) } function factorial(num) { if (num == 1) return 1 return num * factorial(num - 1) } self.addEventListener("message", (evt) => { const num = evt.data const arr = generateBigArray() postMessage(sum(arr)) }) } export default worker// App.js import worker from "./webWorker"import React, { Component } from 'react'; import './index.css';class App extends Component { constructor() { super() this.state = { result: null } } calc = () => { this.webWorker.postMessage(null) } componentDidMount() { let code = worker.toString() code = code.substring(code.indexOf("{") + 1, code.lastIndexOf("}")) const bb = new Blob([code], { type: "application/javascript" }); this.webWorker = new Worker(URL.createObjectURL(bb)) this.webWorker.addEventListener("message", (evt) => { const data = evt.data this.setState({ result: data }) }) } render() { return ( <div> <button onClick = { this.calc }> Sum </button> <h3> Result: { this.state.result }</h3> </div> ) } }
این اپلیکیشن مجموع یک میلیون آیتم آرایه را محاسبه می کند. اگر می خواستیم این محاسبه سنگین را در main thread انجام دهیم، thread اصلی تا پایان محاسبه و نمایش آن در خروجی معطل می ماند.
اما در مثال فوق محاسبه sum را در web worker انجام دادیم. در اینحالت عملیات محاسباتی در یک thread مجزا اجرا می شود و main thread بطور موازی یا parallel به رندر ادامه کدها می پردازد. هر زمان که محاسبه مجموع 1 میلیون آیتم تمام شد نتیجه در خروجی نمایش خواهد یافت. مسلما این روش باعث بهبود سرعت و بهره وری برنامه می شود.
7- تکنیک بارگذاری تنبل یا Lazy loading
بارگذاری تنبل یا Lazy Loading یکی از تکنیک های رایج و محبوب برای افزایش سرعت لود نرم افزار و وب سایت می باشد. به منظور Lazy Load کردن کامپوننت های ریکت، React.lazy() API مورد استفاده قرار می گیرد.
React.lazy ویژگی جدیدی بود که در نسخه 16.6 ریکت ارائه شد. این قابلیت به توسعه دهندگان ری اکت کمک می کند تا براحتی بتوانند بارگذاری تنبل و code=splitting را پیاده سازی کنند.
تابع React.lazy به ما این امکان را می دهد تا یک dynamic import را بصورت یک کامپوننت عادی و regular رندر کنیم.
ساختار کلی React,lazy به این شکل است:
یک تابع بعنوان پارامتر می گیرد:
React.lazy(()=>{})// orfunction cb () {} React.lazy(cb)
این تابع callback باید فایل کامپوننت را با استفاده از dynamic import لود کند. به کد زیر توجه کنید:
// MyComponent.js class MyComponent extends Component{ render() { return <div>MyComponent</div> } }const MyComponent = React.lazy(()=>{import('./MyComponent.js')}) function AppComponent() { return <div><MyComponent /></div> } // orfunction cb () { return import('./MyComponent.js') } const MyComponent = React.lazy(cb) function AppComponent() { return <div><MyComponent /></div> }
تابع کال بک در متد React.lazy یک Promise بر می گرداند. اگر ماژول با موفقیت لود شود این پرامیس Resolve می شود و در صورتی که لود ماژول با شکست مواجه شود Reject خواهد شد. علل عدم لود ماژول می تواند مشکلات شبکه و اینترنت باشد، می تواند no file found باشد، می تواند مسیردهی اشتباه باشد و…
وقتی وب پک وارد کد فوق می شود و می خواهد compile & bundle را انجام دهد به محض رسیدن به React.lazy() یک bundle مجزا ایجاد می کند. در اینصورت اپلیکیشن ما شبیه زیر خواهد شد:
react-app dist/ - index.html - main.b1234.js (contains Appcomponent and bootstrap code) - mycomponent.bc4567.js (contains MyComponent)/** index.html **/ <head> <div id="root"></div> <script src="main.b1234.js"></script> </head>
مشاهده می کنید که اپلیکیشن ما دو فایل bundle جاوا اسکریپتی دارد. وقتی کامپوننت AppComponent می خواهد رندر شود،فایل mycomponent.bc4567.js لود می شود و محتوای آن در DOM نمایش می یابد.
8- ()React.memo
درست مانند useMemo و React.PureComponent متد React.memo() نیز برای cache کردن فانکشنال کامپوننت ها در ری اکت بکار می رود. به قطعه کد زیر توجه نمائید:
function My(props) { return ( <div> {props.data} </div> ) }function App() { const [state, setState] = useState(0) return ( <> <button onClick={()=> setState(0)}>Click</button> <My data={state} /> </> ) }
در App کامپوننت My فراخوانی می شود که شامل یک props بنام data است که مقدارش برابر با state می باشد. اگر روی button کلیک کنیم state برابر با صفر تعریف می شود. اگر چندین بار هم روی دکمه کلیک شود باز هم مقدار state=0 می باشد. با اینکه مقدار state که بصورت props به کامپوننت پاس داده می شود تغییری نمی کند و همیشه صفر است کامپوننت My مجددا رندر یا re-render می شود.
این قضیه باعث می شود سرعت و کارایی برنامه بشدت افت کند.
برای بهبود این وضعیت می توانیم به شکل زیر کامپوننت My را داخل React.memo تعریف کنیم که نسخه کش شده از کامپوننت My را return می کند.
function My(props) { return ( <div> {props.data} </div> ) }const MemoedMy = React.memo(My)function App() { const [state, setState] = useState(0) return ( <> <button onClick={()=> setState(0)}>Click</button> <MemeodMy data={state} /> </> ) }
در اینحالت اگر چند بار هم روی دکمه کلیک کنیم کامپوننت My تنها یکبار trigger و رندر می شود. به این دلیل که React.memo باعث می شود props های کامپوننت کش یا memoize شوند و اگر تغییری در input نداشته باشیم کامپوننت My فقط و فقط برای بار اول رندر می شود.
نکته: کاری که React.PureComponent در کلاس کامپوننت ها انجام می دهد React.memo در فانکشنال کامپوننت انجام می دهد.
9- ()useCallback
useCallback شبیه useMemo کار می کند با این تفاوت که کاربردش caching یا memoize کردن تعریف تابع است. با یک مثال قضیه را روشن می کنیم:
function TestComp(props) { l('rendering TestComp') return ( <> TestComp <button onClick={props.func}>Set Count in 'TestComp'</button> </> ) }TestComp = React.memo(TestComp)function App() { const [count, setCount] = useState(0) return ( <> <button onClick={()=> setCount(count + 1)}>Set Count</button> <TestComp func={()=> setCount(count + 1)} /> </> ) }
در کد بالا یک کامپوننت App داریم که توسط هوک useState مقدار count state را نگه داری می کند. هر زمان که تابع setState فراخوانی می شود، App Component یکبار re-render می شود. در این کامپوننت، یک button و یک کامپوننت TestComp رندر می شود. اگر روی دکمه Set Count کلیک کنیم، App Component بهمراه درخت فرزندانش re-render می شود. اکنون TestComp با استفاده از react memo کش یا memoizedشده تا از رندرهای اضافی و غیر ضروری جلوگیری شود.
React.memo یک کامپوننت را با این روش کش یا memoize می کند: props قبلی کامپوننت را با props جدید کامپوننت مقایسه می کند، در صورتی که تغییری مشاهده کند، کامپوننت re-render می شود وگرنه آن را مجددا رندر نخواهد کرد.
همانطور که در دستور زیر می بینید، کامپوننت TestComp یک اتریبیوت (props) بنام func دارد که کارش چک کردن مقادیر props است.
... return ( <> ... <TestComp func={()=> setCount(count + 1)} /> </> ) ...
اما یک جای کار ایراد دارد. زیرا هر بار TestComp یک نمونه جدید از func prop دریافت می کند. به این دلیل که نحوه تعریف func به شکل arrow function است و هر بار که کامپوننت TestComp صدا زده می شود، یک instance جدید از func ایجاد می شود (به محل دیگری از حافظه اشاره دارد). پس React Memo تصور می کند مقدار props تغییر پیدا کرده و فرمان re-render شدن کامپوننت را صادر می کند.
اکنون چطور می توانیم این مشکل را برطرف کنیم؟
یک روش اینست که بدنه تابع funcرا به خارج از function scope منتقل کنیم. روش خوبی است اما با اینکار به تابع setCount رفرنس نخواهد داشت. اینجا جایی است که useCallback بدرد می خورد. هوک useCallback یک نسخه کش شده از props تابع را بر می گرداند. و ما این مقدار را به عنوان props کامپوننت TestComp در نظر می گیریم. مطابق کد زیر:
function App() { const check = 90 const [count, setCount] = useState(0) const clickHndlr = useCallback(()=> { setCount(check) }, [check]); return ( <> <button onClick={()=> setCount(count + 1)}>Set Count</button> <TestComp func={clickHndlr} /> </> ) }
در این حالت clickHndlr با هر بار re-render شدن App مجددا رندر نخواهد شد. مگر اینکه dependency آن یعنی [check] تغییر کند. بنابراین اگر ما بوطر مداوم هم روی دکمه Set Count کلیک کنیم، کامپوننت re-render نخواهد شد. زیرا مقدار props تغییری نکرده است. هوک useCallback مقدار متغیر check را بررسی می کند. اگر نسبت به مقدار قبلش تغییری داشته باشد، setCount(check) را به عنوان props به کامپوننت TestComp ارسال می کند و منجر به رندر مجدد یا re-render آن می شود. در غیر اینصورت، یعنی اگر مقدار check تغییری نکرده باشد، هیچ کاری انجام نمی دهد. پس react memoعملیات re-render را انجام نخواهد داد.
10- shouldComponentUpdate
یک اپلیکیشن ریکت از چندین کامپوننت تشکیل شده است. از کامپوننت والد یعنی App گرفته تا کامپوننت های فرزندان.
class ReactComponent extends Component { render() { return ( <div></div> ) } }
در قطعه کد بالا یک کامپوننت ساده و basic را مشاهده می کنیم.
ساختار سلسله مراتبی و درختی کامپوننت ها باعث می شود هر زمان که کامپوننت والد تغییری پیدا کرد، کامپوننت های فرزند نیز مطابق آن re-render شوند و به اصطلاح propagate رخ دهد. وقتی یک کامپوننت قرار است re-render شود، مقدار propsو context فعلی آن با props و context قبلی آن مقایسه می شود. اگر مقادیر یکسان باشند اتفاقی رخ نمی دهد وگرنه کامپوننت مجددا رندر خواهد شد.
در واقع ریکت این مقایسه را با رفرنس شی یا object reference انجام می دهد که توسط عملگر تساوی سه گانه یا === (strict equality) آن را اجرا می کند.
پس ری اکت مقادیر آبجکت های state و props را بر اساس رفرنس با هم مقایسه می کند.
class ReactComponent extends Component { constructor(props, context) { super(props, context) this.state = { data: null } this.inputValue = null }handleClick = () => { this.setState({data: this.inputValue}) }onChange = (evt) => { this.inputValue = evt.target.value }render() { console.log("rendering App") return ( <div> {this.state.data} <input onChange={onChange} /> <button onClick={handleCick}>Click Me </button> </div> ) } }
به کامپوننت فوق توجه کنید. در آبجکت state یک data دارد. اگر در تکست باکس مقداری وارد کنیم و دکمه Click Me را بزنیم مقدار وارد شده در input در DOM رندر می شود و نمایش داده می شود. توسط دستور {this.state.data}
ما عمدا در اولین خط متد render() یک کنسول لاگ با محتوای rendering App تعریف کرده ایم که هر بار App رندر شد این پیغام را در کنسول ببینیم.
بعنوان مثال اگر ما عدد 2 را در input تایپ کنیم و دکمه را بزنیم، کامپوننت re-render خواهد شد. زیرا مقدار اولیه state برابر null است و مقدار فعلی آن عدد 2 است.
State قبلی:
state = { data: null }
State فعلی:
state = { data: 2 }
هر بار که متد setState اجرا می شود، یک آبجکت جدید state می سازد که به فضای دیگری از حافظه اشاره یا رفرنس دارد. پس همانطور که قبلا گفتیم عملگر تساوی === دو طرف تساوی را بر اساس نوع و مقدارشان چک می کند و چون رفرنس state دوم با state اول فوق دارد رندز شدن مجدد کامپوننت را در دستو کار قرار می دهد.
حالا اگر مجددا input را با همان عدد 2 مقداردهی کنیم و دکمه را بزنیم، کامپوننت مجددا رندر خواهد شد. در صورتی که ما انتظار داریم re-render رخ ندهد. چون مقدار state قبل و بعد تفاوت ندارد. اما نکته اینجاست که قبلا گفتیم. چون رفرنس آبجکت state قبلی با بعدی فرق دارد و به آدرس متفاوتی از حافظه اشاره دارد، ری اکت تصور می کند مقدار state تغییر کرده و کامپوننت را دوباره render می کند.
این مشکل جایی دردسرساز می شود که چندین کامپوننت زیرمجموعه یا فرزند هم داشته باشیم. در اینصورت عملیات re-rendering روی تمام کامپوننت های فرزند نیز صورت می گیرد و باعث افت کارایی و سرعت اپلیکیشن خواهد شد.
کتابخانه ReactJS برای رفع این مشکل، امکانی را برای توسعه دهندگان فراهم کرده که کنترل رندر شدن کامپوننت را به روش دیگری انجام دهند. یعنی متد shouldComponentUpdate
متد shouldComponentUpdate وقتی صدا زده می شود که کامپوننت در حال رندر شدن باشد. اگر این متد true برگرداند (return کند) کامپوننت re-render می شود و اگر false برگرداند رندر شدن مجدد کامپوننت کنسل می شود.
نحوه تعریف و استفاده از متد shouldComponentUpdate را در مثال زیر میبینیم. این متد دو آرگومان state و props بعدی را بعنوان ورودی می گیرد و به این طریق ما می توانیم لاجیک موردنظر را جهت رندر شدن کامپوننت را پیاده سازی کنیم.
class ReactComponent extends Component { constructor(props, context) { super(props, context) this.state = { data: null } this.inputValue = null }handleClick = () => { this.setState({data: this.inputValue}) }onChange = (evt) => { this.inputValue = evt.target.value }shouldComponentUpdate( nextProps,nextState) { if(nextState.data === this.state.data) return false return true }render() { l("rendering App") return ( <div> {this.state.data} <input onChange={this.onChange} /> <button onClick={this.handleClick}>Click Me </button> </div> ) } }
همانطور که در بدنه متد مشاهده می کنید، دو آرگومان nextProps و nextState را بعنوان ورودی می گیرد. البته نام این آرگومان ها دلخواه است.
shouldComponentUpdate(nextProps, nextState) { if (nextState.data === this.state.data) return false return true }
در این مثال مقدار state قبل را با state بعد مقایسه کرده ایم (nextState.data === this.state.data) اگر تساوی برقرار باشد، متد false را return خواهد کرد و در نتیجه کامپوننت re-render نمی شود. اما اگر تساوی برقرار نباشد متد shouldCmponentUpdate مقدار true را بر می گرداند که باعث re-render شدن کامپوننت می شود.
اکنون اگر یک مقدار ثابت و یکسان مانند عدد 2 را در input بنویسیم و چند بار روی دکمه کلیک کنیم، کامپوننت فقط یکبار re-render خواهد شد. بنابراین استفاده صحیح از متد shouldCmponentUpdate می تواند میزان کارایی و سرعت اپلیکیشن های react را افزایش دهد.
نتیجه گیری:
کتابخانه ری اکت (ReactJS)بی نظیر است. برای تمام نواقص و مشکلات احتمالی یک راه حل بهینه دارد. دقت کنید که نیاز نیست برای تمام اپلیکیشن های ری اکتی خود از روش های ذکر شده در این مقاله استفاده کنید. بهتر است ابتدا اپلیکیشن خود را پیاده سازی کنید و هر جا که نیاز به بهبود کارایی و سرعت بود از روش هایی که در این مقاله مطرح کردیم استفاده کنید.
در نهایت از شما همراهان عزیز آکادمی راهکارینو تقاضا دارم که اگر این مقاله برایتان مفید بود لینک آن را با دوستان خود به اشتراک بگذارید. همچنین در صورتی که سوالی در زمینه بهینه سازی وب اپلیکیشن ریکتی خود دارید از طریق فرم ارسال دیدگاه آن را با ما در میان بگذارید تا تیم پشتیبانی راهکاری نو پاسخگوی شما باشند. تشکر از همراهی همیشگی شما.
مطالب زیر را حتما مطالعه کنید
2 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
ممنونم ، خیلی عالی بود👏
درود بر شما.
خواهش می کنم 🙂
خوشحالم که مفید بوده براتون