ફીડમાં વીસ આઇટમ્સ હોય ત્યારે બધું પરફેક્ટ લાગે છે. સ્ક્રોલિંગ એકદમ સ્મૂધ હોય છે. તમારો ક્લાયન્ટ ખુશ હોય છે. પછી તમે તેને પ્રોડક્શનમાં મોકલો છો, ડેટા આવે છે, અને અચાનક તમે બે હજાર રો (rows) ને જોઈ રહ્યા હોવ છો. UI અટકીવા લાગે છે. મેમરી વધતી જાય છે જ્યાં સુધી OS તેને બંધ ન કરી દે. હતાશામાં, કેટલાક ડેવલપર્સ બધું જ ScrollView માં લપેટી દે છે અને કામ પૂરું કરી દે છે. તે નિર્ણય સામાન્ય રીતે એક બગ ઉકેલવા માટે ત્રણ નવા બગ પેદા કરે છે.

લિસ્ટ એ પરફોર્મન્સનો એવો અવરોધ છે જે નક્કી કરે છે કે યુઝર્સ તમારી React Native એપને કેવી રીતે જોશે. જો તમે તેને યોગ્ય રીતે બનાવશો તો એપ નેટિવ જેવી લાગશે. જો તમે ભૂલ કરશો તો સૌથી સુંદર સ્ક્રીન પણ ધીમી અને કંટાળાજનક બની જશે. તેનું મૂળ કારણ સામાન્ય રીતે તમે પસંદ કરેલા કમ્પોનન્ટ અને તમે JavaScript અને UI threads ને જે કામ કરવા માટે કહો છો, તે વચ્ચેનો અસંતુલન છે. React Native બે ટ્રેક પર ચાલે છે. તમારું લોજિક JS thread પર રહે છે જ્યારે પેઇન્ટિંગ (painting) native UI thread પર થાય છે. જ્યારે તમે કોઈ વિશાળ લિસ્ટને ખોટી રીતે રેન્ડર કરો છો, ત્યારે બંને threads લેઆઉટ કેલ્ક્યુલેશન, re-renders અને મેમરી એલોકેશનમાં ડૂબવા લાગે છે. પરિણામે frames ડ્રોપ થાય છે, સ્ક્રીન ખાલી દેખાય છે અને અંતે એપ ક્રેશ થઈ જાય છે.

સાચું સાધન પસંદ કરો

લિસ્ટ કમ્પોનન્ટ પસંદ કરવું એ એક વિચારશીલ આર્કિટેક્ચરલ નિર્ણય હોવો જોઈએ, માત્ર એક રિફ્લેક્સ (reflex) નહીં.

ScrollView એ સૌથી સરળ વિકલ્પ છે. તે તમે આપેલા દરેક ચાઇલ્ડને લે છે, દરેકને તરત જ મેમરીમાં માઉન્ટ કરે છે, અને આખું લિસ્ટ નેટિવ સ્ક્રોલ એન્જિનને સોંપી દે છે. સેટિંગ્સ સ્ક્રીન, લોગિન ફોર્મ અથવા દસ સેક્શન ધરાવતા સ્ટેટિક પ્રોડક્ટ ડિટેલ પેજ જેવા ટૂંકા અને ફિક્સ્ડ કન્ટેન્ટ માટે આ બરાબર છે. તે અનુમાનિત (predictable) છે અને સ્ટાઇલ કરવામાં સરળ છે. પણ મુશ્કેલી એ છે કે તેમાં વર્ચ્યુલાઇઝેશન (virtualization) નથી. જો તમે તેને બે હજાર આઇટમ્સ આપશો, તો તે આજ્ઞાકતપણે બે હજાર નેટિવ વ્યૂઝ (native views) બનાવશે. મોટા અથવા ડાયનેમિક ડેટા સેટ માટે ScrollView નો ઉપયોગ કરશો નહીં. તેને લાઈબ્રેરીના શેલ્ફ તરીકે નહીં, પણ ફ્રેમ કરેલા પોસ્ટર તરીકે વિચારો.

FlatList એ લાંબા અને સમાન ફીડ માટે કામદાર છે. તે કન્ટેન્ટને વર્ચ્યુલાઇઝ કરે છે, જેનો અર્થ છે કે તે ફક્ત એ જ રો (rows) ને માઉન્ટ કરે છે જે હાલમાં દેખાય છે અથવા વ્યૂપોર્ટ (viewport) ની નજીક છે. જેમ યુઝર સ્ક્રોલ કરે છે, તેમ FlatList સ્ક્રીન પરથી બહાર નીકળી જતી સેલ્સ (cells) ને અનમાઉન્ટ કરે છે અને આવતા ડેટા માટે તેનો પુનઃઉપયોગ (recycle) કરે છે. આનાથી તમારો એરે (array) ગમે તેટલો મોટો થાય, મેમરી સ્થિર રહે છે. જો તમે સોશિયલ ટાઈમલાઈન, નોટિફિકેશન સેન્ટર અથવા સમાન કાર્ડ્સનું સતત સ્ક્રોલ થતું કલેક્શન બનાવી રહ્યા હોવ, તો FlatList એ ડિફોલ્ટ સાચો વિકલ્પ છે.

SectionList એ વ્યવસ્થિત રીતે ગોઠવાયેલું FlatList છે. જ્યારે તમારો ડેટા ગ્રુપ કરેલા બકેટમાં આવે છે, જેમ કે મૂળાક્ષરો પ્રમાણે ગોઠવાયેલું એડ્રેસ બુક, તારીખ મુજબ વહેંચાયેલું વર્કઆઉટ લોગ અથવા મહિના મુજબ ગોઠવાયેલું ઇન્વોઇસ લિસ્ટ, ત્યારે તેનો ઉપયોગ કરો. તે સ્ટીકી સેક્શન હેડર્સ (sticky section headers) રેન્ડર કરે છે અને ગ્રુપિંગ લોજિક સંભાળે છે. તે અંદરથી FlatList જેવું જ વર્ચ્યુલાઇઝેશન એન્જિન વાપરે છે, તેથી તમને ટાઇટલવાળા વિભાગોના વધારાના માળખા સાથે સમાન મેમરી ફાયદા મળે છે.

FlashList ત્યારે કામ આવે છે જ્યારે તમારે ઉપકરણમાંથી છેલ્લો ફ્રેમ પણ મેળવવો હોય. RecyclerListView ઇકોસિસ્ટમ પર બનેલું, તે FlatList કરતા વધુ આક્રમક રીતે વ્યૂઝને રિસાયકલ કરે છે અને મધ્યમ શ્રેણીના હાર્ડવેર પર પણ સેકન્ડ દીઠ સાઠ ફ્રેમ્સ (sixty frames per second) જાળવી રાખવાનું લક્ષ્ય રાખે છે. જો તમે હાઈ-વોલ્યુમ ચેટ ઇન્ટરફેસ, ઝડપી સ્ક્રોલિંગ ધરાવતું પ્રોડક્ટ કેટલોગ અથવા એવી કોઈપણ સ્ક્રીન બનાવી રહ્યા હોવ જ્યાં સ્મૂધનેસ એ સ્પર્ધાત્મક ફાયદો હોય, તો FlashList વધારાની ડિપેન્ડન્સી (dependency) માટે યોગ્ય છે. તે દરેક સ્ક્રીન માટે જરૂરી નથી, પરંતુ મુખ્ય અનુભવ નક્કી કરતા ફીડ્સ માટે, પરફોર્મન્સમાં તફાવત નોંધપાત્ર હોય છે.

સામાન્ય પરફોર્મન્સ બગાડનારા પરિબળો

જ્યારે લિસ્ટ ધીમું થવા લાગે ત્યારે ત્રણ સામાન્ય કારણો જવાબદાર હોય છે.

એકસાથે ઘણા બધા React trees ને માઉન્ટ કરવું એ સૌથી મોટું નિષ્ફળતાનું કારણ છે. જ્યારે દરેક રો એક જટિલ કમ્પોનન્ટ ટ્રી હોય છે, ત્યારે પ્રારંભિક રેન્ડરિંગ JS thread ને એટલા સમય માટે રોકી શકે છે કે જેનાથી સફેદ સ્ક્રીન દેખાય અથવા પ્રથમ પેઇન્ટિંગમાં વિલંબ થાય. યુઝર એપ ખોલે છે અને રાહ જુએ છે. પ્રારંભિક લોડ પછી પણ, ભારે રો (heavy rows) સ્ક્રોલ શરૂઆતને ધીમી બનાવે છે કારણ કે પ્રથમ થોડા ફ્રેમ્સ સેટઅપના કામમાં વપરાઈ જાય છે.

દરેક ફ્રેમ દીઠ વધુ પડતું કામ સ્ક્રોલ દરમિયાન ધ્રુજારી (stuttering) તરીકે દેખાય છે. એનિમેશન સ્મૂધ રાખવા માટે તમારી પાસે દરેક ફ્રેમ દીઠ અંદાજે સોળ મિલીસેકન્ડનું બજેટ છે. જો રો કમ્પોનન્ટ મોંઘી ગણતરીઓ કરે છે, તારીખનું તાત્કાલિક પાર્સિંગ (parses dates on the fly) કરે છે, અથવા render ની અંદર ઊંડા ઓબ્જેક્ટ સરખામણી (deep object comparisons) કરે છે, તો તમે તે બજેટ વટાવી જશો. UI thread ફ્રેમ્સ ડ્રોપ કરે છે અને યુઝરને ઝટકો અનુભવાય છે.

અતિશય મેમરીનો ઉપયોગ એ શાંત હત્યારો છે. દરેક નેટિવ વ્યૂ (native view) માટે RAM વપરાય છે. જો તમે મોટા અનઓપ્ટિમાઇઝ્ડ ફોટા, દરેક કાર્ડ પર ડ્રોપ શેડો અથવા નેસ્ટેડ ટચેબલ્સ (nested touchables) ઉમેરો છો, તો મેમરીનો વપરાશ વધી જાય છે. iOS પર સિસ્ટમ ચેતવણી આપ્યા વગર તમારી એપ બંધ કરી શકે છે. Android પર યુઝર લેગ (lag) વધતો જુએ છે જ્યાં સુધી એપ વાપરવી અશક્ય ન બની જાય.

ઓપ્ટિમાઇઝેશન ચેકલિસ્ટ

નાની વ્યૂહાત્મક આદતો એક એવી યાદીને જે માત્ર કામ કરે છે તેનાથી અલગ પાડે છે જે અત્યંત ઝડપી અને કાર્યક્ષમ છે.

સ્થિર (stable) keys નો ઉપયોગ કરો. તમારા ડેટા સેટમાંથી હંમેશા key prop માં વાસ્તવિક ઓળખકર્તા (identifier) પસાર કરો. ક્યારેય એરે ઇન્ડેક્સ (array index) નો ઉપયોગ કરશો નહીં. જો તમારી યાદી ફરીથી ગોઠવાય (reorder), ફિલ્ટર થાય અથવા નવી વસ્તુઓ ઉમેરાય, તો ઇન્ડેક્સ-આધારિત key React ને ખોટા ડેટાને ખોટા રિસાયકલ થયેલા ઘટક (component) સાથે જોડવા માટે છેતરે છે. આ ભૂલ બિનજરૂરી unmounts, સ્ટેટ મિસમેચ અને કેસ્કેડિંગ re-renders ને ઉત્તેજિત કરે છે. યોગ્ય ID React ને ચોક્કસપણે જણાવે છે કે કઈ row ક્યાં ખસી છે.

રો (rows) ને memoize કરો. તમારા row component ને React.memo માં લપેટી (wrap) દો જેથી તે ત્યારે જ re-render થાય જ્યારે તેના props ખરેખર બદલાય. આ સુરક્ષા વિના, કોઈપણ parent state update દરેક દેખાતી row માં render pass ટ્રિગર કરી શકે છે, ભલે તેમનો ડેટા સમાન હોય. લાંબી યાદીમાં, આ બિનજરૂરી સાયકલ ઝડપથી વધી જાય છે.

renderItem ને સ્થિર રાખો. દરેક parent render પર renderItem prop ની અંદર સીધી નવી ફંક્શન વ્યાખ્યાયિત કરવાનું ટાળો. renderItem={({ item }) => <Row data={item} />} જેવી inline arrow function દરેક વખતે parent અપડેટ થાય ત્યારે નવો રેફરન્સ બનાવે છે. FlatList બદલાયેલ prop જુએ છે અને બિનજરૂરી રીતે row ને રિસાયકલ કરે છે. render ફંક્શનને component ની બહાર વ્યાખ્યાયિત કરો અથવા useCallback સાથે તેને memoize કરો જેથી રેફરન્સ સ્થિર રહે.

જ્યારે પણ શક્ય હોય ત્યારે getItemLayout નો ઉપયોગ કરો. જો તમારી rows ની ઊંચાઈ (height) નિશ્ચિત અથવા અનુમાનિત હોય, તો FlatList ને ચોક્કસ જણાવો કે તે શું છે. આ prop યાદીને ખર્ચાળ (expensive) native measurement calls ને સ્કીપ કરવાની મંજૂરી આપે છે. mount થયા પછી દરેક સેલને માપવાને બદલે, યાદી ગાણિતિક રીતે સ્થાનની ગણતરી કરે છે. સેંકડો અથવા હજારો આઇટમ્સ ધરાવતી યાદીઓમાં તફાવત ખાસ કરીને સ્પષ્ટ દેખાય છે, જ્યાં onLayout Chatter JS thread ને ધીમો કરી શકે છે.

ઇમેજને આક્રમક રીતે (aggressively) ઓપ્ટિમાઇઝ કરો. અનબાઉન્ડેડ (unbounded) ઇમેજ યાદી માટે ઝેર સમાન છે. હંમેશા સ્પષ્ટ width અને height સેટ કરો જેથી ઇમેજ ડિકોડ થાય તે પહેલાં native layer જગ્યા અનામત રાખે. રિમોટ ઇમેજ માટે, Expo Image જેવી caching library અથવા તેના સમાન લાઇબ્રેરીનો ઉપયોગ કરો જે memory caching, disk persistence અને format optimization સંભાળે છે. ડિફોલ્ટ React Native Image component પ્રોટોટાઇપ માટે કામ કરે છે, પરંતુ પ્રોડક્શન ફીડ્સ માટે મેમરી અને લોડિંગ સ્ટેટ્સ પર વધુ નિયંત્રણની જરૂર હોય છે.

scroll containers ને નેસ્ટેડ (nest) કરવાનું ટાળો. ક્યારેય વર્ટિકલ FlatList ને વર્ટિકલ ScrollView ની અંદર ન મૂકો. Parent ScrollView તમામ scroll ઇવેન્ટ્સને કેપ્ચર કરે છે અને child FlatList ની તેના viewport ને માપવાની ક્ષમતામાં અવરોધ ઊભો કરે છે. Virtualization તૂટી જાય છે કારણ કે FlatList ને હવે ખબર નથી હોતી કે કઈ rows દેખાવી જોઈએ. પરિણામે, દરેક row ગમે તેમ mount થાય છે, જે virtualization ના સમગ્ર હેતુને નિષ્ફળ બનાવે છે. જો તમારે યાદીની ઉપર હેડરની જરૂર હોય, તો FlatList ના પોતાના ListHeaderComponent prop નો ઉપયોગ કરો. જો તમારે જટિલ sticky behavior ની જરૂર હોય, તો યોગ્ય header configuration સાથે SectionList અથવા FlashList નો ઉપયોગ કરો.

સુવર્ણ નિયમ (The Golden Rule)

જો સામગ્રી (content) નાની અને મર્યાદિત હોય, તો ScrollView ને તે સંભાળવા દો. જો સામગ્રી user-generated ડેટા અથવા રિમોટ પેજીનેશન સાથે વધતી હોય, તો virtualized list નો ઉપયોગ કરો. જ્યારે યાદી એપનું મુખ્ય કેન્દ્ર હોય અને વપરાશકર્તાઓ એક સમયે મિનિટો સુધી સ્ક્રોલ કરે, ત્યારે FlashList નો ઉપયોગ કરો.

અહીં એક છેલ્કું સત્ય છે જે ભૂલી જવું સરળ છે. સાધારણ (Boring) rows ઝડપથી સ્ક્રોલ થાય છે. તમારું row component જેટલું હલકું હશે, તમારી યાદી તેટલી જ સ્મૂધ હશે. વ્યક્તિગત row માંથી nested navigations, ભારે ગણતરીઓ (heavy computations) અને બિનજરૂરી એનિમેશન દૂર કરો. Markup ને ફ્લેટ રાખો, લોજિકને પાતળું (thin) રાખો અને ઇમેજનું કદ યોગ્ય રાખો. યાદી તેના દ્વારા રેન્ડર કરવામાં આવતા સામગ્રીના સંચિત વજન (cumulative weight) દ્વારા જીવે છે અથવા મરી જાય છે. દરેક row ને હલકી (cheap) બનાવો, અને યાદી શ્રેષ્ઠ રીતે પ્રીમિયમ (expensive) અનુભવાશે.