React માં Suspense નો ઉપયોગ કરીને Parallel Data Fetching ની અદ્યતન તકનીકોનું અન્વેષણ કરો, જે એપ્લિકેશનના પ્રદર્શન અને વપરાશકર્તાના અનુભવને વધારે છે.
React Suspense Coordination: Parallel Data Fetching Strategies માં નિપુણતા
React Suspense એ અસુમેળ કામગીરીઓ, ખાસ કરીને ડેટા ફેચિંગને કેવી રીતે હેન્ડલ કરીએ છીએ તેમાં ક્રાંતિ લાવી છે. તે ડેટા લોડ થવાની રાહ જોતી વખતે ઘટકોને રેન્ડરિંગ "સસ્પેન્ડ" કરવાની મંજૂરી આપે છે, જે લોડિંગ સ્ટેટ્સને સંચાલિત કરવાની એક ઘોષણાત્મક રીત પ્રદાન કરે છે. જોકે, વ્યક્તિગત ડેટા ફેચને Suspense સાથે લપેટવાથી વોટરફોલ અસર થઈ શકે છે, જ્યાં એક ફેચ આગામી શરૂ થાય તે પહેલાં પૂર્ણ થાય છે, જે પ્રદર્શન પર નકારાત્મક અસર કરે છે. આ બ્લોગ પોસ્ટ Suspense નો ઉપયોગ કરીને બહુવિધ ડેટા ફેચને સમાંતર સંકલિત કરવા, તમારી એપ્લિકેશનની રિસ્પોન્સિવનેસને ઓપ્ટિમાઇઝ કરવા અને વૈશ્વિક પ્રેક્ષકો માટે વપરાશકર્તા અનુભવને વધારવા માટેની અદ્યતન વ્યૂહરચનાઓમાં ઊંડા ઉતરે છે.
Data Fetching માં Waterfall Problem સમજવું
એવી પરિસ્થિતિની કલ્પના કરો જ્યાં તમારે વપરાશકર્તાનું નામ, અવતાર અને તાજેતરની પ્રવૃત્તિ સાથેનું પ્રોફાઇલ દર્શાવવાની જરૂર છે. જો તમે દરેક ડેટાને ક્રમિક રીતે ફેચ કરો છો, તો વપરાશકર્તા નામ માટે લોડિંગ સ્પિનર, પછી અવતાર માટે બીજું, અને છેવટે, પ્રવૃત્તિ ફીડ માટે એક જુએ છે. આ ક્રમિક લોડિંગ પેટર્ન વોટરફોલ અસર બનાવે છે, સંપૂર્ણ પ્રોફાઇલના રેન્ડરિંગમાં વિલંબ કરે છે અને વપરાશકર્તાઓને નિરાશ કરે છે. વિવિધ નેટવર્ક ગતિ ધરાવતા આંતરરાષ્ટ્રીય વપરાશકર્તાઓ માટે, આ વિલંબ વધુ સ્પષ્ટ થઈ શકે છે.
આ સરળ કોડ સ્નિપેટ ધ્યાનમાં લો:
function UserProfile() {
const name = useName(); // વપરાશકર્તા નામ ફેચ કરે છે
const avatar = useAvatar(name); // નામ પર આધારિત અવતાર ફેચ કરે છે
const activity = useActivity(name); // નામ પર આધારિત પ્રવૃત્તિ ફેચ કરે છે
return (
<div>
<h2>{name}</h2>
<img src={avatar} alt="User Avatar" />
<ul>
{activity.map(item => <li key={item.id}>{item.text}</li>) }
</ul>
</div>
);
}
આ ઉદાહરણમાં, useAvatar અને useActivity useName ના પરિણામ પર આધારિત છે. આ સ્પષ્ટ વોટરફોલ બનાવે છે - useAvatar અને useActivity useName પૂર્ણ થયા પછી જ ડેટા ફેચ કરવાનું શરૂ કરી શકે છે. આ બિનકાર્યક્ષમ છે અને એક સામાન્ય પ્રદર્શન અવરોધ છે.
Suspense સાથે Parallel Data Fetching માટે Strategies
Suspense સાથે ડેટા ફેચિંગને ઓપ્ટિમાઇઝ કરવાની ચાવી એ છે કે બધા ડેટા વિનંતીઓ સમાંતર શરૂ કરવી. અહીં કેટલીક વ્યૂહરચનાઓ છે જે તમે લાગુ કરી શકો છો:
1. `React.preload` અને Resources સાથે ડેટા પ્રીલોડ કરવો
સૌથી શક્તિશાળી તકનીકોમાંની એક ઘટક રેન્ડર થાય તે પહેલાં ડેટા પ્રીલોડ કરવાની છે. આમાં "રિસોર્સ" (ડેટા ફેચિંગ પ્રોમિસને સમાવતો object) બનાવવો અને ડેટા પ્રી-ફેચ કરવાનો સમાવેશ થાય છે. `React.preload` આમાં મદદ કરે છે. જ્યારે ઘટકને ડેટાની જરૂર પડે, ત્યારે તે પહેલેથી જ ઉપલબ્ધ હોય છે, જે લગભગ સંપૂર્ણપણે લોડિંગ સ્ટેટને દૂર કરે છે.
પ્રોડક્ટ ફેચ કરવા માટે એક રિસોર્સ ધ્યાનમાં લો:
const createProductResource = (productId) => {
let promise;
let product;
let error;
const suspender = new Promise((resolve, reject) => {
promise = fetch(`/api/products/${productId}`)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
product = data;
resolve();
})
.catch(e => {
error = e;
reject(e);
});
});
return {
read() {
if (error) {
throw error;
}
if (product) {
return product;
}
throw suspender;
},
};
};
// ઉપયોગ:
const productResource = createProductResource(123);
function ProductDetails() {
const product = productResource.read();
return (<div>{product.name}</div>);
}
હવે, તમે ProductDetails ઘટક રેન્ડર થાય તે પહેલાં આ રિસોર્સને પ્રીલોડ કરી શકો છો. ઉદાહરણ તરીકે, રૂટ ટ્રાન્ઝિશન દરમિયાન અથવા હોવર પર.
React.preload(productResource);
આ ખાતરી કરે છે કે ProductDetails ઘટકને જરૂર પડે તે સમયે ડેટા ઉપલબ્ધ થવાની સંભાવના છે, જે લોડિંગ સ્ટેટને ઘટાડે છે અથવા દૂર કરે છે.
2. `Promise.all` નો ઉપયોગ કરીને Concurrent Data Fetching
બીજો સરળ અને અસરકારક અભિગમ એ છે કે એક જ Suspense બાઉન્ડ્રીની અંદર સમાંતર રીતે બધા ડેટા ફેચ શરૂ કરવા માટે Promise.all નો ઉપયોગ કરવો. જ્યારે ડેટા નિર્ભરતા અગાઉથી જાણીતી હોય ત્યારે આ સારી રીતે કાર્ય કરે છે.
ચાલો વપરાશકર્તા પ્રોફાઇલ ઉદાહરણ પર પાછા આવીએ. ક્રમિક રીતે ડેટા ફેચ કરવાને બદલે, અમે નામ, અવતાર અને પ્રવૃત્તિ ફીડ સમાંતર રીતે ફેચ કરી શકીએ છીએ:
import { useState, useEffect, Suspense } from 'react';
async function fetchName() {
// API કોલનું અનુકરણ કરો
await new Promise(resolve => setTimeout(resolve, 500));
return 'John Doe';
}
async function fetchAvatar(name) {
// API કોલનું અનુકરણ કરો
await new Promise(resolve => setTimeout(resolve, 300));
return `https://example.com/avatars/${name.toLowerCase().replace(' ', '-')}.jpg`;
}
async function fetchActivity(name) {
// API કોલનું અનુકરણ કરો
await new Promise(resolve => setTimeout(resolve, 800));
return [
{ id: 1, text: 'Posted a photo' },
{ id: 2, text: 'Updated profile' },
];
}
function useSuspense(promise) {
const [result, setResult] = useState(null);
useEffect(() => {
let didCancel = false;
promise.then(
(data) => {
if (!didCancel) {
setResult({ status: 'success', value: data });
}
},
(error) => {
if (!didCancel) {
setResult({ status: 'error', value: error });
}
}
);
return () => {
didCancel = true;
};
}, [promise]);
if (result?.status === 'success') {
return result.value;
} else if (result?.status === 'error') {
throw result.value;
} else {
throw promise;
}
}
function Name() {
const name = useSuspense(fetchName());
return <h2>{name}</h2>;
}
function Avatar({ name }) {
const avatar = useSuspense(fetchAvatar(name));
return <img src={avatar} alt="User Avatar" />;
}
function Activity({ name }) {
const activity = useSuspense(fetchActivity(name));
return (
<ul>
{activity.map(item => <li key={item.id}>{item.text}</li>) }
</ul>
);
}
function UserProfile() {
const name = useSuspense(fetchName());
return (
<div>
<Suspense fallback={<div>Loading Avatar...</div>}>
<Avatar name={name} />
</Suspense>
<Suspense fallback={<div>Loading Activity...</div>}>
<Activity name={name} />
</Suspense>
</div>
);
}
export default UserProfile;
જોકે, જો `Avatar` અને `Activity` બંને `fetchName` પર આધાર રાખે છે, પરંતુ અલગ Suspense બાઉન્ડ્રીમાં રેન્ડર થાય છે, તો તમે `fetchName` પ્રોમિસને પેરેન્ટ પર લિફ્ટ કરી શકો છો અને તેને React Context દ્વારા પ્રદાન કરી શકો છો.
import React, { createContext, useContext, useState, useEffect, Suspense } from 'react';
async function fetchName() {
// API કોલનું અનુકરણ કરો
await new Promise(resolve => setTimeout(resolve, 500));
return 'John Doe';
}
async function fetchAvatar(name) {
// API કોલનું અનુકરણ કરો
await new Promise(resolve => setTimeout(resolve, 300));
return `https://example.com/avatars/${name.toLowerCase().replace(' ', '-')}.jpg`;
}
async function fetchActivity(name) {
// API કોલનું અનુકરણ કરો
await new Promise(resolve => setTimeout(resolve, 800));
return [
{ id: 1, text: 'Posted a photo' },
{ id: 2, text: 'Updated profile' },
];
}
function useSuspense(promise) {
const [result, setResult] = useState(null);
useEffect(() => {
let didCancel = false;
promise.then(
(data) => {
if (!didCancel) {
setResult({ status: 'success', value: data });
}
},
(error) => {
if (!didCancel) {
setResult({ status: 'error', value: error });
}
}
);
return () => {
didCancel = true;
};
}, [promise]);
if (result?.status === 'success') {
return result.value;
} else if (result?.status === 'error') {
throw result.value;
} else {
throw promise;
}
}
const NamePromiseContext = createContext(null);
function Avatar() {
const namePromise = useContext(NamePromiseContext);
const name = useSuspense(namePromise);
const avatar = useSuspense(fetchAvatar(name));
return <img src={avatar} alt="User Avatar" />;
}
function Activity() {
const namePromise = useContext(NamePromiseContext);
const name = useSuspense(namePromise);
const activity = useSuspense(fetchActivity(name));
return (
<ul>
{activity.map(item => <li key={item.id}>{item.text}</li>) }
</ul>
);
}
function UserProfile() {
const namePromise = fetchName();
return (
<NamePromiseContext.Provider value={namePromise}>
<Suspense fallback={<div>Loading Avatar...</div>}>
<Avatar />
</Suspense>
<Suspense fallback={<div>Loading Activity...</div>}>
<Activity />
</Suspense>
</NamePromiseContext.Provider>
);
}
export default UserProfile;
3. Parallel Fetches મેનેજ કરવા માટે Custom Hook નો ઉપયોગ કરવો
સંભવિતપણે શરતી ડેટા નિર્ભરતા સાથે વધુ જટિલ પરિસ્થિતિઓ માટે, તમે Parallel Data Fetching નું સંચાલન કરવા અને Suspense ઉપયોગ કરી શકે તેવું રિસોર્સ પરત કરવા માટે કસ્ટમ હૂક બનાવી શકો છો.
import { useState, useEffect, useRef } from 'react';
function useParallelData(fetchFunctions) {
const [resource, setResource] = useState(null);
const mounted = useRef(true);
useEffect(() => {
mounted.current = true;
const promises = fetchFunctions.map(fn => fn());
const suspender = Promise.all(promises).then(
(results) => {
if (mounted.current) {
setResource({ status: 'success', value: results });
}
},
(error) => {
if (mounted.current) {
setResource({ status: 'error', value: error });
}
}
);
setResource({
status: 'pending',
value: suspender,
});
return () => {
mounted.current = false;
};
}, [fetchFunctions]);
const read = () => {
if (!resource) {
throw new Error('Resource not yet initialized');
}
if (resource.status === 'pending') {
throw resource.value;
}
if (resource.status === 'error') {
throw resource.value;
}
return resource.value;
};
return { read };
}
// ઉદાહરણ ઉપયોગ:
async function fetchUserData(userId) {
// API કોલનું અનુકરણ કરો
await new Promise(resolve => setTimeout(resolve, 300));
return { id: userId, name: 'User ' + userId };
}
async function fetchUserPosts(userId) {
// API કોલનું અનુકરણ કરો
await new Promise(resolve => setTimeout(resolve, 500));
return [{ id: 1, title: 'Post 1' }, { id: 2, title: 'Post 2' }];
}
function UserProfile({ userId }) {
const { read } = useParallelData([
() => fetchUserData(userId),
() => fetchUserPosts(userId),
]);
const [userData, userPosts] = read();
return (
<div>
<h2>{userData.name}</h2>
<ul>
{userPosts.map(post => <li key={post.id}>{post.title}</li>) }
</ul>
</div>
);
}
function App() {
return (
<Suspense fallback={<div>Loading user data...</div>}>
<UserProfile userId={123} />
</Suspense>
);
}
export default App;
આ અભિગમ પ્રોમિસ અને લોડિંગ સ્ટેટ્સના સંચાલનની જટિલતાને હૂકમાં સમાવે છે, જે ઘટક કોડને સ્વચ્છ અને ડેટા રેન્ડરિંગ પર વધુ કેન્દ્રિત બનાવે છે.
4. Streaming Server Rendering સાથે Selective Hydration
સર્વર-રેન્ડર્ડ એપ્લિકેશન્સ માટે, React 18 પસંદગીયુક્ત હાઇડ્રેશન સાથે સ્ટ્રીમિંગ સર્વર રેન્ડરિંગનો પરિચય આપે છે. આ તમને સર્વર પર ઉપલબ્ધ થતાંની સાથે જ HTML ના ભાગોને ક્લાયંટ પર મોકલવાની મંજૂરી આપે છે. તમે ધીમા-લોડિંગ ઘટકોને <Suspense> બાઉન્ડ્રીઝ સાથે લપેટ કરી શકો છો, જે ધીમા ઘટકો સર્વર પર હજી પણ લોડ થઈ રહ્યા હોય ત્યારે બાકીના પૃષ્ઠને ઇન્ટરેક્ટિવ બનવાની મંજૂરી આપે છે. આ ધારણા કરેલ પ્રદર્શનને નાટકીય રીતે સુધારે છે, ખાસ કરીને ધીમા નેટવર્ક કનેક્શન્સ અથવા ઉપકરણો ધરાવતા વપરાશકર્તાઓ માટે.
એવી પરિસ્થિતિ ધ્યાનમાં લો જ્યાં સમાચાર વેબસાઇટને વિશ્વના વિવિધ પ્રદેશો (દા.ત., એશિયા, યુરોપ, અમેરિકા) માંથી લેખો પ્રદર્શિત કરવાની જરૂર છે. કેટલાક ડેટા સ્ત્રોતો અન્ય કરતા ધીમા હોઈ શકે છે. પસંદગીયુક્ત હાઇડ્રેશન ઝડપી પ્રદેશોમાંથી લેખો પ્રથમ પ્રદર્શિત કરવાની મંજૂરી આપે છે, જ્યારે ધીમા પ્રદેશોમાંથી હજી પણ લોડ થઈ રહ્યા હોય, ત્યારે સમગ્ર પૃષ્ઠને અવરોધિત થતું અટકાવે છે.
Errors અને Loading States હેન્ડલ કરવા
જ્યારે Suspense લોડિંગ સ્ટેટ મેનેજમેન્ટને સરળ બનાવે છે, ત્યારે error હેન્ડલિંગ નિર્ણાયક રહે છે. Error boundaries (componentDidCatch lifecycle method અથવા `react-error-boundary` જેવી લાઇબ્રેરીઓમાંથી `useErrorBoundary` હૂકનો ઉપયોગ કરીને) તમને ડેટા ફેચિંગ અથવા રેન્ડરિંગ દરમિયાન થતી errors ને ગ્રેસફુલી હેન્ડલ કરવાની મંજૂરી આપે છે. આ error boundaries ને ચોક્કસ Suspense બાઉન્ડ્રીઝની અંદર errors પકડવા માટે વ્યૂહાત્મક રીતે મૂકવા જોઈએ, જે સમગ્ર એપ્લિકેશનને ક્રેશ થવાથી અટકાવે છે.
import React, { Suspense } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
function MyComponent() {
// ... ડેટા ફેચ કરે છે જે error કરી શકે છે
}
function App() {
return (
<ErrorBoundary fallback={<div>Something went wrong!</div>}>
<Suspense fallback={<div>Loading...</div>}>
<MyComponent />
</Suspense>
</ErrorBoundary>
);
}
લોડિંગ અને error બંને સ્ટેટ્સ માટે માહિતીપ્રદ અને વપરાશકર્તા-મૈત્રીપૂર્ણ fallback UI પ્રદાન કરવાનું યાદ રાખો. આ આંતરરાષ્ટ્રીય વપરાશકર્તાઓ માટે ખાસ કરીને મહત્વપૂર્ણ છે જેઓ ધીમી નેટવર્ક ગતિ અથવા પ્રાદેશિક સેવા આઉટેજિસનો સામનો કરી રહ્યા હોય.
Suspense સાથે Data Fetching ઓપ્ટિમાઇઝ કરવા માટે Best Practices
- Critical Data ઓળખો અને પ્રાધાન્ય આપો: તમારી એપ્લિકેશનના પ્રારંભિક રેન્ડરિંગ માટે કયો ડેટા આવશ્યક છે તે નક્કી કરો અને તે ડેટાને પ્રથમ ફેચ કરવાને પ્રાધાન્ય આપો.
- શક્ય હોય ત્યારે ડેટા પ્રીલોડ કરો: ઘટકોને જરૂર પડે તે પહેલાં ડેટા પ્રીલોડ કરવા માટે `React.preload` અને રિસોર્સનો ઉપયોગ કરો, જે લોડિંગ સ્ટેટ્સને ઘટાડે છે.
- ડેટા સમાંતર ફેચ કરો: બહુવિધ ડેટા ફેચ સમાંતર રીતે શરૂ કરવા માટે `Promise.all` અથવા કસ્ટમ હૂક્સનો ઉપયોગ કરો.
- API Endpoints ઓપ્ટિમાઇઝ કરો: ખાતરી કરો કે તમારા API endpoints પ્રદર્શન માટે ઓપ્ટિમાઇઝ થયેલ છે, જે વિલંબ અને પેલોડ કદ ઘટાડે છે. તમને જે ડેટાની જરૂર છે તે જ મેળવવા માટે GraphQL જેવી તકનીકોનો ઉપયોગ કરવાનું વિચારો.
- Caching લાગુ કરો: API વિનંતીઓની સંખ્યા ઘટાડવા માટે વારંવાર access થતા ડેટાને કેશ કરો. મજબૂત કેશિંગ ક્ષમતાઓ માટે `swr` અથવા `react-query` જેવી લાઇબ્રેરીઓનો ઉપયોગ કરવાનું વિચારો.
- Code Splitting નો ઉપયોગ કરો: પ્રારંભિક લોડ સમય ઘટાડવા માટે તમારી એપ્લિકેશનને નાના ભાગોમાં વિભાજીત કરો. તમારી એપ્લિકેશનના વિવિધ ભાગોને progressivly લોડ અને રેન્ડર કરવા માટે Suspense સાથે code splitting ને જોડો.
- પ્રદર્શન પર દેખરેખ રાખો: પ્રદર્શન અવરોધોને ઓળખવા અને સંબોધવા માટે Lighthouse અથવા WebPageTest જેવા સાધનોનો ઉપયોગ કરીને તમારી એપ્લિકેશનના પ્રદર્શન પર નિયમિતપણે દેખરેખ રાખો.
- Errors ને ગ્રેસફુલી હેન્ડલ કરો: ડેટા ફેચિંગ અને રેન્ડરિંગ દરમિયાન errors પકડવા માટે error boundaries લાગુ કરો, વપરાશકર્તાઓને માહિતીપ્રદ error સંદેશાઓ પ્રદાન કરો.
- Server-Side Rendering (SSR) ધ્યાનમાં લો: SEO અને પ્રદર્શન કારણોસર, ઝડપી પ્રારંભિક અનુભવ પહોંચાડવા માટે સ્ટ્રીમિંગ અને પસંદગીયુક્ત હાઇડ્રેશન સાથે SSR નો ઉપયોગ કરવાનું વિચારો.
Conclusion
React Suspense, જ્યારે Parallel Data Fetching માટેની વ્યૂહરચનાઓ સાથે જોડાયેલ હોય, ત્યારે રિસ્પોન્સિવ અને પર્ફોર્મન્ટ વેબ એપ્લિકેશન્સ બનાવવા માટે એક શક્તિશાળી ટૂલકિટ પ્રદાન કરે છે. વોટરફોલ સમસ્યાને સમજીને અને પ્રીલોડિંગ, `Promise.all` સાથે સમાંતર ફેચિંગ અને કસ્ટમ હૂક્સ જેવી તકનીકો લાગુ કરીને, તમે વપરાશકર્તા અનુભવને નોંધપાત્ર રીતે સુધારી શકો છો. Errors ને ગ્રેસફુલી હેન્ડલ કરવાનું અને પ્રદર્શન પર દેખરેખ રાખવાનું યાદ રાખો જેથી તમારી એપ્લિકેશન વિશ્વભરના વપરાશકર્તાઓ માટે ઓપ્ટિમાઇઝ રહે. જેમ જેમ React વિકસિત થતું રહે છે, સ્ટ્રીમિંગ સર્વર રેન્ડરિંગ સાથે પસંદગીયુક્ત હાઇડ્રેશન જેવી નવી સુવિધાઓનું અન્વેષણ કરવું તમારા વપરાશકર્તા અનુભવોને પહોંચાડવાની તમારી ક્ષમતાને વધુ વધારશે, ભલે તે સ્થાન અથવા નેટવર્ક શરતોને ધ્યાનમાં લીધા વિના. આ તકનીકો અપનાવીને, તમે એવી એપ્લિકેશન્સ બનાવી શકો છો જે માત્ર કાર્યાત્મક નથી, પરંતુ તમારા વૈશ્વિક પ્રેક્ષકો માટે વાપરવામાં આનંદદાયક પણ છે.
આ બ્લોગ પોસ્ટનો હેતુ React Suspense સાથે Parallel Data Fetching Strategies નું વ્યાપક વિહંગાવલોકન પ્રદાન કરવાનો હતો. અમને આશા છે કે તમને તે માહિતીપ્રદ અને મદદરૂપ લાગ્યું. અમે તમને તમારી પોતાની પ્રોજેક્ટ્સમાં આ તકનીકો સાથે પ્રયોગ કરવા અને તમારા તારણો સમુદાય સાથે શેર કરવા પ્રોત્સાહિત કરીએ છીએ.