മലയാളം

കോഡ് സ്പ്ലിറ്റിംഗിനപ്പുറം ഡാറ്റാ ഫെച്ചിംഗിനായി റിയാക്ട് സസ്പെൻസ് ഉപയോഗിക്കാം. ഫെച്ച്-ആസ്-യു-റെൻഡർ, എറർ ഹാൻഡ്ലിംഗ്, ആഗോള ആപ്ലിക്കേഷനുകൾക്കുള്ള നൂതന പാറ്റേണുകൾ എന്നിവ മനസ്സിലാക്കുക.

റിയാക്ട് സസ്പെൻസ് റിസോഴ്സ് ലോഡിംഗ്: ആധുനിക ഡാറ്റാ ഫെച്ചിംഗ് രീതികളിൽ വൈദഗ്ദ്ധ്യം നേടാം

വെബ് ഡെവലപ്‌മെൻ്റിൻ്റെ ചലനാത്മകമായ ലോകത്ത്, യൂസർ എക്സ്പീരിയൻസ് (UX) ആണ് ഏറ്റവും പ്രധാനം. നെറ്റ്‌വർക്ക് സാഹചര്യങ്ങളോ ഉപകരണത്തിൻ്റെ കഴിവുകളോ പരിഗണിക്കാതെ, ആപ്ലിക്കേഷനുകൾ വേഗതയേറിയതും പ്രതികരണശേഷിയുള്ളതും ആനന്ദകരവുമാകുമെന്ന് പ്രതീക്ഷിക്കുന്നു. റിയാക്ട് ഡെവലപ്പർമാരെ സംബന്ധിച്ചിടത്തോളം, ഇത് പലപ്പോഴും സങ്കീർണ്ണമായ സ്റ്റേറ്റ് മാനേജ്മെൻ്റ്, ലോഡിംഗ് ഇൻഡിക്കേറ്ററുകൾ, ഡാറ്റാ ഫെച്ചിംഗ് വാട്ടർഫാളുകൾക്കെതിരായ നിരന്തരമായ പോരാട്ടം എന്നിവയിലേക്ക് നയിക്കുന്നു. ഇവിടെയാണ് റിയാക്ട് സസ്പെൻസ് വരുന്നത്. അസിൻക്രണസ് പ്രവർത്തനങ്ങൾ, പ്രത്യേകിച്ച് ഡാറ്റാ ഫെച്ചിംഗ്, കൈകാര്യം ചെയ്യുന്ന രീതിയെ അടിസ്ഥാനപരമായി മാറ്റാൻ രൂപകൽപ്പന ചെയ്ത ശക്തമായ, എന്നാൽ പലപ്പോഴും തെറ്റിദ്ധരിക്കപ്പെടുന്ന ഒരു ഫീച്ചറാണിത്.

ആദ്യമായി React.lazy() ഉപയോഗിച്ച് കോഡ് സ്പ്ലിറ്റിംഗിനായി അവതരിപ്പിച്ച സസ്പെൻസിൻ്റെ യഥാർത്ഥ സാധ്യത, എപിഐ-യിൽ നിന്നുള്ള ഡാറ്റ ഉൾപ്പെടെയുള്ള ഏതൊരു അസിൻക്രണസ് റിസോഴ്സും ലോഡ് ചെയ്യുന്നത് ഏകോപിപ്പിക്കാനുള്ള കഴിവിലാണ്. ഈ സമഗ്രമായ ഗൈഡ്, റിസോഴ്സ് ലോഡിംഗിനായി റിയാക്ട് സസ്പെൻസിനെക്കുറിച്ച് ആഴത്തിൽ പരിശോധിക്കും. അതിൻ്റെ പ്രധാന ആശയങ്ങൾ, അടിസ്ഥാനപരമായ ഡാറ്റാ ഫെച്ചിംഗ് പാറ്റേണുകൾ, മികച്ച പ്രകടനവും പ്രതിരോധശേഷിയുമുള്ള ആഗോള ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിനുള്ള പ്രായോഗിക പരിഗണനകൾ എന്നിവയും ഇതിൽ പര്യവേക്ഷണം ചെയ്യും.

റിയാക്ടിലെ ഡാറ്റാ ഫെച്ചിംഗിൻ്റെ പരിണാമം: ഇംപറേറ്റീവിൽ നിന്ന് ഡിക്ലറേറ്റീവിലേക്ക്

വർഷങ്ങളായി, റിയാക്ട് കമ്പോണൻ്റുകളിലെ ഡാറ്റാ ഫെച്ചിംഗ് ഒരു സാധാരണ പാറ്റേണിനെയാണ് ആശ്രയിച്ചിരുന്നത്: ഒരു എപിഐ കോൾ ആരംഭിക്കാൻ useEffect ഹുക്ക് ഉപയോഗിക്കുക, useState ഉപയോഗിച്ച് ലോഡിംഗ്, എറർ സ്റ്റേറ്റുകൾ കൈകാര്യം ചെയ്യുക, ഈ സ്റ്റേറ്റുകളെ അടിസ്ഥാനമാക്കി സോപാധികമായി റെൻഡർ ചെയ്യുക. ഇത് പ്രവർത്തനക്ഷമമായിരുന്നെങ്കിലും, പലപ്പോഴും പല വെല്ലുവിളികൾക്കും ഇടയാക്കി:

സസ്പെൻസ് ഇല്ലാതെ ഒരു സാധാരണ ഡാറ്റാ ഫെച്ചിംഗ് സാഹചര്യം പരിഗണിക്കുക:

import React, { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchUser = async () => {
      try {
        setIsLoading(true);
        const response = await fetch(`/api/users/${userId}`);
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const data = await response.json();
        setUser(data);
      } catch (e) {
        setError(e);
      } finally {
        setIsLoading(false);
      }
    };
    fetchUser();
  }, [userId]);

  if (isLoading) {
    return <p>ഉപയോക്താവിൻ്റെ പ്രൊഫൈൽ ലോഡ് ചെയ്യുന്നു...</p>;
  }

  if (error) {
    return <p style={"color: red;"}>പിശക്: {error.message}</p>;
  }

  if (!user) {
    return <p>ഉപയോക്തൃ ഡാറ്റ ലഭ്യമല്ല.</p>;
  }

  return (
    <div>
      <h2>ഉപയോക്താവ്: {user.name}</h2>
      <p>ഇമെയിൽ: {user.email}</p>
      <!-- കൂടുതൽ ഉപയോക്തൃ വിവരങ്ങൾ -->
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>ആപ്ലിക്കേഷനിലേക്ക് സ്വാഗതം</h1>
      <UserProfile userId={"123"} />
    </div>
  );
}

ഈ പാറ്റേൺ സർവ്വവ്യാപിയാണ്, പക്ഷേ ഇത് അതിൻ്റേതായ അസിൻക്രണസ് സ്റ്റേറ്റ് കൈകാര്യം ചെയ്യാൻ കമ്പോണൻ്റിനെ നിർബന്ധിക്കുന്നു. ഇത് പലപ്പോഴും യുഐയും ഡാറ്റാ ഫെച്ചിംഗ് ലോജിക്കും തമ്മിൽ ഒരു ശക്തമായ ബന്ധത്തിന് ഇടയാക്കുന്നു. സസ്പെൻസ് കൂടുതൽ ഡിക്ലറേറ്റീവും ലളിതവുമായ ഒരു ബദൽ വാഗ്ദാനം ചെയ്യുന്നു.

കോഡ് സ്പ്ലിറ്റിംഗിനപ്പുറം റിയാക്ട് സസ്പെൻസ് മനസ്സിലാക്കുന്നു

മിക്ക ഡെവലപ്പർമാരും കോഡ് സ്പ്ലിറ്റിംഗിനായി React.lazy() വഴിയാണ് സസ്പെൻസിനെ ആദ്യമായി പരിചയപ്പെടുന്നത്. ഒരു കമ്പോണൻ്റിൻ്റെ കോഡ് ആവശ്യമുള്ളപ്പോൾ മാത്രം ലോഡ് ചെയ്യാൻ ഇത് നിങ്ങളെ അനുവദിക്കുന്നു. ഉദാഹരണത്തിന്:

import React, { Suspense, lazy } from 'react';

const LazyComponent = lazy(() => import('./MyHeavyComponent'));

function App() {
  return (
    <Suspense fallback={<div>കമ്പോണൻ്റ് ലോഡ് ചെയ്യുന്നു...</div>}>
      <LazyComponent />
    </Suspense>
  );
}

ഈ സാഹചര്യത്തിൽ, MyHeavyComponent ഇതുവരെ ലോഡ് ചെയ്തിട്ടില്ലെങ്കിൽ, <Suspense> ബൗണ്ടറി lazy() ത്രോ ചെയ്യുന്ന പ്രോമിസ് പിടിച്ചെടുക്കുകയും കമ്പോണൻ്റിൻ്റെ കോഡ് തയ്യാറാകുന്നതുവരെ fallback പ്രദർശിപ്പിക്കുകയും ചെയ്യും. ഇവിടുത്തെ പ്രധാന ആശയം ഇതാണ്: റെൻഡറിംഗ് സമയത്ത് ത്രോ ചെയ്യുന്ന പ്രോമിസുകളെ പിടിച്ചെടുക്കുന്നതിലൂടെയാണ് സസ്പെൻസ് പ്രവർത്തിക്കുന്നത്.

ഈ സംവിധാനം കോഡ് ലോഡിംഗിന് മാത്രമുള്ളതല്ല. റെൻഡറിംഗ് സമയത്ത് വിളിക്കപ്പെടുന്ന ഏതൊരു ഫംഗ്ഷനും (ഉദാഹരണത്തിന്, ഒരു റിസോഴ്സ് ലഭ്യമല്ലാത്തതുകൊണ്ട്) ഒരു പ്രോമിസ് ത്രോ ചെയ്താൽ, കമ്പോണൻ്റ് ട്രീയിലെ മുകളിലുള്ള ഒരു സസ്പെൻസ് ബൗണ്ടറിക്ക് അത് പിടിച്ചെടുക്കാൻ കഴിയും. പ്രോമിസ് റിസോൾവ് ചെയ്യുമ്പോൾ, റിയാക്ട് കമ്പോണൻ്റ് വീണ്ടും റെൻഡർ ചെയ്യാൻ ശ്രമിക്കുന്നു, റിസോഴ്സ് ഇപ്പോൾ ലഭ്യമാണെങ്കിൽ, ഫാൾബാക്ക് മറയ്ക്കുകയും യഥാർത്ഥ ഉള്ളടക്കം പ്രദർശിപ്പിക്കുകയും ചെയ്യുന്നു.

ഡാറ്റാ ഫെച്ചിംഗിനുള്ള സസ്പെൻസിൻ്റെ പ്രധാന ആശയങ്ങൾ

ഡാറ്റാ ഫെച്ചിംഗിനായി സസ്പെൻസ് ഉപയോഗിക്കുന്നതിന്, നമ്മൾ ചില പ്രധാന തത്വങ്ങൾ മനസ്സിലാക്കേണ്ടതുണ്ട്:

1. ഒരു പ്രോമിസ് ത്രോ ചെയ്യുന്നു

പ്രോമിസുകൾ റിസോൾവ് ചെയ്യാൻ async/await ഉപയോഗിക്കുന്ന പരമ്പരാഗത അസിൻക്രണസ് കോഡിൽ നിന്ന് വ്യത്യസ്തമായി, ഡാറ്റ തയ്യാറായിട്ടില്ലെങ്കിൽ ഒരു പ്രോമിസ് *ത്രോ* ചെയ്യുന്ന ഫംഗ്ഷനെയാണ് സസ്പെൻസ് ആശ്രയിക്കുന്നത്. അത്തരം ഒരു ഫംഗ്ഷൻ വിളിക്കുന്ന ഒരു കമ്പോണൻ്റ് റെൻഡർ ചെയ്യാൻ റിയാക്ട് ശ്രമിക്കുമ്പോൾ, ഡാറ്റ ഇപ്പോഴും പെൻഡിംഗിലാണെങ്കിൽ, പ്രോമിസ് ത്രോ ചെയ്യപ്പെടുന്നു. റിയാക്ട് തുടർന്ന് ആ കമ്പോണൻ്റിൻ്റെയും അതിൻ്റെ ചിൽഡ്രൻ്റെയും റെൻഡറിംഗ് 'താൽക്കാലികമായി നിർത്തി', അടുത്തുള്ള <Suspense> ബൗണ്ടറിക്കായി തിരയുന്നു.

2. സസ്പെൻസ് ബൗണ്ടറി

<Suspense> കമ്പോണൻ്റ് പ്രോമിസുകൾക്കുള്ള ഒരു എറർ ബൗണ്ടറിയായി പ്രവർത്തിക്കുന്നു. ഇത് ഒരു fallback പ്രോപ്പ് എടുക്കുന്നു, അതിൻ്റെ ഏതെങ്കിലും ചിൽഡ്രൻ (അല്ലെങ്കിൽ അവരുടെ പിൻഗാമികൾ) സസ്പെൻഡ് ചെയ്യുമ്പോൾ (അതായത്, ഒരു പ്രോമിസ് ത്രോ ചെയ്യുമ്പോൾ) റെൻഡർ ചെയ്യാനുള്ള യുഐ ആണിത്. അതിൻ്റെ സബ്ട്രീയിൽ ത്രോ ചെയ്ത എല്ലാ പ്രോമിസുകളും റിസോൾവ് ചെയ്തുകഴിഞ്ഞാൽ, ഫാൾബാക്കിന് പകരം യഥാർത്ഥ ഉള്ളടക്കം വരും.

ഒരൊറ്റ സസ്പെൻസ് ബൗണ്ടറിക്ക് ഒന്നിലധികം അസിൻക്രണസ് പ്രവർത്തനങ്ങൾ കൈകാര്യം ചെയ്യാൻ കഴിയും. ഉദാഹരണത്തിന്, ഒരേ <Suspense> ബൗണ്ടറിക്കുള്ളിൽ നിങ്ങൾക്ക് രണ്ട് കമ്പോണൻ്റുകളുണ്ടെങ്കിൽ, ഓരോന്നിനും ഡാറ്റ ഫെച്ച് ചെയ്യേണ്ടതുണ്ടെങ്കിൽ, രണ്ട് ഡാറ്റാ ഫെച്ചുകളും പൂർത്തിയാകുന്നതുവരെ ഫാൾബാക്ക് പ്രദർശിപ്പിക്കും. ഇത് ഭാഗികമായ യുഐ കാണിക്കുന്നത് ഒഴിവാക്കുകയും കൂടുതൽ ഏകോപിതമായ ലോഡിംഗ് അനുഭവം നൽകുകയും ചെയ്യുന്നു.

3. കാഷെ/റിസോഴ്സ് മാനേജർ (യൂസർലാൻഡ് ഉത്തരവാദിത്തം)

പ്രധാനമായി, സസ്പെൻസ് സ്വയം ഡാറ്റാ ഫെച്ചിംഗോ കാഷിംഗോ കൈകാര്യം ചെയ്യുന്നില്ല. ഇത് വെറുമൊരു ഏകോപന സംവിധാനം മാത്രമാണ്. ഡാറ്റാ ഫെച്ചിംഗിനായി സസ്പെൻസ് പ്രവർത്തിക്കാൻ, നിങ്ങൾക്ക് ഇനിപ്പറയുന്ന കാര്യങ്ങൾ ചെയ്യുന്ന ഒരു ലെയർ ആവശ്യമാണ്:

ഈ 'റിസോഴ്സ് മാനേജർ' സാധാരണയായി ഓരോ റിസോഴ്സിൻ്റെയും അവസ്ഥ (പെൻഡിംഗ്, റിസോൾവ്ഡ്, അല്ലെങ്കിൽ എറർ) സംഭരിക്കുന്നതിന് ലളിതമായ ഒരു കാഷെ (ഉദാഹരണത്തിന്, ഒരു Map അല്ലെങ്കിൽ ഒരു ഒബ്ജക്റ്റ്) ഉപയോഗിച്ച് നടപ്പിലാക്കുന്നു. ഇത് പ്രദർശന ആവശ്യങ്ങൾക്കായി നിങ്ങൾക്ക് സ്വമേധയാ നിർമ്മിക്കാമെങ്കിലും, ഒരു യഥാർത്ഥ ആപ്ലിക്കേഷനിൽ, നിങ്ങൾ സസ്പെൻസുമായി സംയോജിപ്പിക്കുന്ന ഒരു ശക്തമായ ഡാറ്റാ ഫെച്ചിംഗ് ലൈബ്രറി ഉപയോഗിക്കണം.

4. കൺകറൻ്റ് മോഡ് (റിയാക്ട് 18-ൻ്റെ മെച്ചപ്പെടുത്തലുകൾ)

റിയാക്ടിൻ്റെ പഴയ പതിപ്പുകളിൽ സസ്പെൻസ് ഉപയോഗിക്കാമെങ്കിലും, അതിൻ്റെ പൂർണ്ണ ശക്തി കൺകറൻ്റ് റിയാക്ടിലാണ് (റിയാക്ട് 18-ൽ createRoot ഉപയോഗിച്ച് ഡിഫോൾട്ടായി പ്രവർത്തനക്ഷമമാക്കിയിരിക്കുന്നു) അഴിച്ചുവിടുന്നത്. റെൻഡറിംഗ് ജോലി തടസ്സപ്പെടുത്താനും, താൽക്കാലികമായി നിർത്താനും, പുനരാരംഭിക്കാനും കൺകറൻ്റ് മോഡ് റിയാക്ടിനെ അനുവദിക്കുന്നു. ഇതിനർത്ഥം:

സസ്പെൻസ് ഉപയോഗിച്ചുള്ള ഡാറ്റാ ഫെച്ചിംഗ് പാറ്റേണുകൾ

സസ്പെൻസിൻ്റെ വരവോടെ ഡാറ്റാ ഫെച്ചിംഗ് പാറ്റേണുകളിലെ പരിണാമം നമുക്ക് പര്യവേക്ഷണം ചെയ്യാം.

പാറ്റേൺ 1: ഫെച്ച്-ദെൻ-റെൻഡർ (സസ്പെൻസ് റാപ്പിംഗോടു കൂടിയ പരമ്പരാഗതം)

ഇതൊരു ക്ലാസിക് സമീപനമാണ്. ഇവിടെ ഡാറ്റ ഫെച്ച് ചെയ്ത ശേഷം മാത്രമാണ് കമ്പോണൻ്റ് റെൻഡർ ചെയ്യുന്നത്. ഡാറ്റയ്ക്കായി 'ത്രോ പ്രോമിസ്' മെക്കാനിസം നേരിട്ട് ഉപയോഗിക്കുന്നില്ലെങ്കിലും, ഒടുവിൽ ഡാറ്റ റെൻഡർ ചെയ്യുന്ന ഒരു കമ്പോണൻ്റിനെ ഒരു ഫാൾബാക്ക് നൽകാൻ സസ്പെൻസ് ബൗണ്ടറിയിൽ പൊതിയാൻ നിങ്ങൾക്ക് കഴിയും. ഇത് സസ്പെൻസിനെ ഒരു പൊതുവായ ലോഡിംഗ് യുഐ ഓർക്കസ്‌ട്രേറ്ററായി ഉപയോഗിക്കുന്നതിനാണ്, കമ്പോണൻ്റുകൾ ഒടുവിൽ തയ്യാറാകുമ്പോൾ, അവയുടെ ആന്തരിക ഡാറ്റാ ഫെച്ചിംഗ് ഇപ്പോഴും പരമ്പരാഗത useEffect അടിസ്ഥാനമാക്കിയുള്ളതാണെങ്കിലും.

import React, { Suspense, useState, useEffect } from 'react';

function UserDetails({ userId }) {
  const [user, setUser] = useState(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const fetchUserData = async () => {
      setIsLoading(true);
      const res = await fetch(`/api/users/${userId}`);
      const data = await res.json();
      setUser(data);
      setIsLoading(false);
    };
    fetchUserData();
  }, [userId]);

  if (isLoading) {
    return <p>ഉപയോക്താവിൻ്റെ വിവരങ്ങൾ ലോഡ് ചെയ്യുന്നു...</p>;
  }

  return (
    <div>
      <h3>ഉപയോക്താവ്: {user.name}</h3>
      <p>ഇമെയിൽ: {user.email}</p>
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>ഫെച്ച്-ദെൻ-റെൻഡർ ഉദാഹരണം</h1>
      <Suspense fallback={<div>പേജ് ലോഡ് ചെയ്യുന്നു...</div>}>
        <UserDetails userId={"1"} />
      </Suspense>
    </div>
  );
}

ഗുണങ്ങൾ: മനസ്സിലാക്കാൻ എളുപ്പമാണ്, പിന്നോക്കം പൊരുത്തപ്പെടുന്നു. ഒരു ഗ്ലോബൽ ലോഡിംഗ് സ്റ്റേറ്റ് വേഗത്തിൽ ചേർക്കാൻ ഇത് ഉപയോഗിക്കാം.

ദോഷങ്ങൾ: UserDetails-നുള്ളിലെ ആവർത്തന കോഡ് ഇല്ലാതാക്കുന്നില്ല. കമ്പോണൻ്റുകൾ തുടർച്ചയായി ഡാറ്റ ഫെച്ച് ചെയ്താൽ വാട്ടർഫാളുകൾക്ക് സാധ്യതയുണ്ട്. ഡാറ്റയ്ക്കായി സസ്പെൻസിൻ്റെ 'ത്രോ-ആൻഡ്-ക്യാച്ച്' മെക്കാനിസം ശരിയായി ഉപയോഗിക്കുന്നില്ല.

പാറ്റേൺ 2: റെൻഡർ-ദെൻ-ഫെച്ച് (റെൻഡറിനുള്ളിൽ ഫെച്ചിംഗ്, പ്രൊഡക്ഷന് വേണ്ടിയുള്ളതല്ല)

സസ്പെൻസ് ഉപയോഗിച്ച് നേരിട്ട് എന്ത് ചെയ്യാൻ പാടില്ല എന്ന് വ്യക്തമാക്കുന്നതിനാണ് ഈ പാറ്റേൺ. കാരണം ഇത് സൂക്ഷ്മമായി കൈകാര്യം ചെയ്തില്ലെങ്കിൽ അനന്തമായ ലൂപ്പുകൾക്കോ പ്രകടന പ്രശ്നങ്ങൾക്കോ ഇടയാക്കും. ഒരു ശരിയായ കാഷിംഗ് മെക്കാനിസം *ഇല്ലാതെ*, ഒരു കമ്പോണൻ്റിൻ്റെ റെൻഡർ ഘട്ടത്തിൽ നേരിട്ട് ഡാറ്റ ഫെച്ച് ചെയ്യാനോ സസ്പെൻഡിംഗ് ഫംഗ്ഷൻ വിളിക്കാനോ ശ്രമിക്കുന്നതാണ് ഇതിൽ ഉൾപ്പെടുന്നത്.

// പ്രൊഡക്ഷനിൽ ശരിയായ കാഷിംഗ് ലെയർ ഇല്ലാതെ ഇത് ഉപയോഗിക്കരുത്
// ഇത് ഒരു നേരിട്ടുള്ള 'ത്രോ' എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് ആശയപരമായി കാണിക്കുന്നതിന് മാത്രമാണ്.

let fetchedData = null;
let dataPromise = null;

function fetchDataSynchronously(url) {
  if (fetchedData) {
    return fetchedData;
  }

  if (!dataPromise) {
    dataPromise = fetch(url)
      .then(res => res.json())
      .then(data => { fetchedData = data; dataPromise = null; return data; })
      .catch(err => { dataPromise = null; throw err; });
  }
  throw dataPromise; // ഇവിടെയാണ് സസ്പെൻസ് പ്രവർത്തിക്കുന്നത്
}

function UserDetailsBadExample({ userId }) {
  const user = fetchDataSynchronously(`/api/users/${userId}`);
  return (
    <div>
      <h3>ഉപയോക്താവ്: {user.name}</h3>
      <p>ഇമെയിൽ: {user.email}</p>
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>റെൻഡർ-ദെൻ-ഫെച്ച് (വിശദീകരണത്തിന് മാത്രം, നേരിട്ട് ശുപാർശ ചെയ്യുന്നില്ല)</h1>
      <Suspense fallback={<div>ഉപയോക്താവിനെ ലോഡ് ചെയ്യുന്നു...</div>}>
        <UserDetailsBadExample userId={"2"} />
      </Suspense>
    </div>
  );
}

ഗുണങ്ങൾ: ഒരു കമ്പോണൻ്റിന് എങ്ങനെ നേരിട്ട് ഡാറ്റ 'ചോദിക്കാമെന്നും' തയ്യാറല്ലെങ്കിൽ സസ്പെൻഡ് ചെയ്യാമെന്നും കാണിക്കുന്നു.

ദോഷങ്ങൾ: പ്രൊഡക്ഷന് വളരെ പ്രശ്നകരമാണ്. ഈ മാനുവൽ, ഗ്ലോബൽ fetchedData, dataPromise സിസ്റ്റം ലളിതമാണ്, ഒന്നിലധികം അഭ്യർത്ഥനകൾ, ഇൻവാലിഡേഷൻ, അല്ലെങ്കിൽ എറർ സ്റ്റേറ്റുകൾ എന്നിവ ശക്തമായി കൈകാര്യം ചെയ്യുന്നില്ല. ഇത് 'ത്രോ-എ-പ്രോമിസ്' എന്ന ആശയത്തിൻ്റെ ഒരു പ്രാകൃതമായ ചിത്രീകരണമാണ്, സ്വീകരിക്കേണ്ട ഒരു പാറ്റേണല്ല.

പാറ്റേൺ 3: ഫെച്ച്-ആസ്-യു-റെൻഡർ (അനുയോജ്യമായ സസ്പെൻസ് പാറ്റേൺ)

ഡാറ്റാ ഫെച്ചിംഗിനായി സസ്പെൻസ് ശരിക്കും പ്രാപ്തമാക്കുന്ന മാതൃകാപരമായ മാറ്റമാണിത്. ഒരു കമ്പോണൻ്റ് റെൻഡർ ചെയ്യുന്നതുവരെ അതിൻ്റെ ഡാറ്റ ഫെച്ച് ചെയ്യാൻ കാത്തിരിക്കുന്നതിനുപകരം, അല്ലെങ്കിൽ എല്ലാ ഡാറ്റയും മുൻകൂട്ടി ഫെച്ച് ചെയ്യുന്നതിനുപകരം, ഫെച്ച്-ആസ്-യു-റെൻഡർ എന്നാൽ നിങ്ങൾ എത്രയും വേഗം ഡാറ്റ ഫെച്ച് ചെയ്യാൻ തുടങ്ങുന്നു എന്നാണ് അർത്ഥമാക്കുന്നത്, പലപ്പോഴും റെൻഡറിംഗ് പ്രക്രിയയ്ക്ക് *മുമ്പോ* അല്ലെങ്കിൽ *അതിനോടൊപ്പം*. കമ്പോണൻ്റുകൾ പിന്നീട് ഒരു കാഷെയിൽ നിന്ന് ഡാറ്റ 'വായിക്കുന്നു', ഡാറ്റ തയ്യാറായിട്ടില്ലെങ്കിൽ, അവ സസ്പെൻഡ് ചെയ്യുന്നു. ഡാറ്റാ ഫെച്ചിംഗ് ലോജിക്കിനെ കമ്പോണൻ്റിൻ്റെ റെൻഡറിംഗ് ലോജിക്കിൽ നിന്ന് വേർതിരിക്കുക എന്നതാണ് പ്രധാന ആശയം.

ഫെച്ച്-ആസ്-യു-റെൻഡർ നടപ്പിലാക്കാൻ, നിങ്ങൾക്ക് ഇനിപ്പറയുന്നവയ്ക്കുള്ള ഒരു സംവിധാനം ആവശ്യമാണ്:

  1. കമ്പോണൻ്റിൻ്റെ റെൻഡർ ഫംഗ്ഷന് പുറത്ത് ഒരു ഡാറ്റാ ഫെച്ച് ആരംഭിക്കുക (ഉദാഹരണത്തിന്, ഒരു റൂട്ടിൽ പ്രവേശിക്കുമ്പോൾ, അല്ലെങ്കിൽ ഒരു ബട്ടൺ ക്ലിക്കുചെയ്യുമ്പോൾ).
  2. പ്രോമിസ് അല്ലെങ്കിൽ റിസോൾവ് ചെയ്ത ഡാറ്റ ഒരു കാഷെയിൽ സംഭരിക്കുക.
  3. കമ്പോണൻ്റുകൾക്ക് ഈ കാഷെയിൽ നിന്ന് 'വായിക്കാൻ' ഒരു വഴി നൽകുക. ഡാറ്റ ഇതുവരെ ലഭ്യമല്ലെങ്കിൽ, റീഡ് ഫംഗ്ഷൻ പെൻഡിംഗ് പ്രോമിസ് ത്രോ ചെയ്യുന്നു.

ഈ പാറ്റേൺ വാട്ടർഫാൾ പ്രശ്നം പരിഹരിക്കുന്നു. രണ്ട് വ്യത്യസ്ത കമ്പോണൻ്റുകൾക്ക് ഡാറ്റ ആവശ്യമുണ്ടെങ്കിൽ, അവയുടെ അഭ്യർത്ഥനകൾ സമാന്തരമായി ആരംഭിക്കാൻ കഴിയും, ഒരൊറ്റ സസ്പെൻസ് ബൗണ്ടറി വഴി ഏകോപിപ്പിച്ച്, രണ്ടും തയ്യാറായാൽ മാത്രമേ യുഐ ദൃശ്യമാകൂ.

മാനുവൽ ഇംപ്ലിമെൻ്റേഷൻ (മനസ്സിലാക്കുന്നതിന്)

അടിസ്ഥാന മെക്കാനിക്സ് മനസ്സിലാക്കാൻ, നമുക്ക് ഒരു ലളിതമായ മാനുവൽ റിസോഴ്സ് മാനേജർ സൃഷ്ടിക്കാം. ഒരു യഥാർത്ഥ ആപ്ലിക്കേഷനിൽ, നിങ്ങൾ ഒരു സമർപ്പിത ലൈബ്രറി ഉപയോഗിക്കും.

import React, { Suspense } from 'react';

// --- ലളിതമായ കാഷെ/റിസോഴ്സ് മാനേജർ --- //
const cache = new Map();

function createResource(promise) {
  let status = 'pending';
  let result;
  let suspender = promise.then(
    (r) => {
      status = 'success';
      result = r;
    },
    (e) => {
      status = 'error';
      result = e;
    }
  );

  return {
    read() {
      if (status === 'pending') {
        throw suspender;
      } else if (status === 'error') {
        throw result;
      } else if (status === 'success') {
        return result;
      }
    },
  };
}

function fetchData(key, fetcher) {
  if (!cache.has(key)) {
    cache.set(key, createResource(fetcher()));
  }
  return cache.get(key);
}

// --- ഡാറ്റാ ഫെച്ചിംഗ് ഫംഗ്ഷനുകൾ --- //
const fetchUserById = (id) => {
  console.log(`ഉപയോക്താവ് ${id}-നെ ഫെച്ച് ചെയ്യുന്നു...`);
  return new Promise(resolve => setTimeout(() => {
    const users = {
      '1': { id: '1', name: 'ആലീസ് സ്മിത്ത്', email: 'alice@example.com' },
      '2': { id: '2', name: 'ബോബ് ജോൺസൺ', email: 'bob@example.com' },
      '3': { id: '3', name: 'ചാർളി ബ്രൗൺ', email: 'charlie@example.com' }
    };
    resolve(users[id]);
  }, 1500));
};

const fetchPostsByUserId = (userId) => {
  console.log(`ഉപയോക്താവ് ${userId}-ൻ്റെ പോസ്റ്റുകൾ ഫെച്ച് ചെയ്യുന്നു...`);
  return new Promise(resolve => setTimeout(() => {
    const posts = {
      '1': [{ id: 'p1', title: 'എൻ്റെ ആദ്യ പോസ്റ്റ്' }, { id: 'p2', title: 'യാത്രാ സാഹസികതകൾ' }],
      '2': [{ id: 'p3', title: 'കോഡിംഗ് ഉൾക്കാഴ്ചകൾ' }],
      '3': [{ id: 'p4', title: 'ആഗോള പ്രവണതകൾ' }, { id: 'p5', title: 'പ്രാദേശിക വിഭവങ്ങൾ' }]
    };
    resolve(posts[userId] || []);
  }, 2000));
};

// --- കമ്പോണൻ്റുകൾ --- //
function UserProfile({ userId }) {
  const userResource = fetchData(`user-${userId}`, () => fetchUserById(userId));
  const user = userResource.read(); // ഉപയോക്തൃ ഡാറ്റ തയ്യാറായില്ലെങ്കിൽ ഇത് സസ്പെൻഡ് ചെയ്യും

  return (
    <div>
      <h3>ഉപയോക്താവ്: {user.name}</h3>
      <p>ഇമെയിൽ: {user.email}</p>
    </div>
  );
}

function UserPosts({ userId }) {
  const postsResource = fetchData(`posts-${userId}`, () => fetchPostsByUserId(userId));
  const posts = postsResource.read(); // പോസ്റ്റ് ഡാറ്റ തയ്യാറായില്ലെങ്കിൽ ഇത് സസ്പെൻഡ് ചെയ്യും

  return (
    <div>
      <h4>{userId} എഴുതിയ പോസ്റ്റുകൾ:</h4>
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
        {posts.length === 0 && <li>പോസ്റ്റുകളൊന്നും കണ്ടെത്തിയില്ല.</li>}
      </ul>
    </div>
  );
}

// --- ആപ്ലിക്കേഷൻ --- //
let initialUserResource = null;
let initialPostsResource = null;

function prefetchDataForUser(userId) {
  initialUserResource = fetchData(`user-${userId}`, () => fetchUserById(userId));
  initialPostsResource = fetchData(`posts-${userId}`, () => fetchPostsByUserId(userId));
}

// App കമ്പോണൻ്റ് റെൻഡർ ചെയ്യുന്നതിന് മുമ്പ് കുറച്ച് ഡാറ്റ പ്രീ-ഫെച്ച് ചെയ്യുക
prefetchDataForUser('1');

function App() {
  return (
    <div>
      <h1>സസ്പെൻസ് ഉപയോഗിച്ച് ഫെച്ച്-ആസ്-യു-റെൻഡർ</h1>
      <p>സസ്പെൻസിൻ്റെ സഹായത്തോടെ ഡാറ്റാ ഫെച്ചിംഗ് എങ്ങനെ സമാന്തരമായി നടക്കുന്നു എന്ന് ഇത് കാണിക്കുന്നു.</p>

      <Suspense fallback={<div>ഉപയോക്തൃ പ്രൊഫൈലും പോസ്റ്റുകളും ലോഡ് ചെയ്യുന്നു...</div>}>
        <UserProfile userId={"1"} />
        <UserPosts userId={"1"} />
      </Suspense>

      <h2>മറ്റൊരു വിഭാഗം</h2>
      <Suspense fallback={<div>വ്യത്യസ്ത ഉപയോക്താവിനെ ലോഡ് ചെയ്യുന്നു...</div>}>
        <UserProfile userId={"2"} />
      </Suspense>
    </div>
  );
}

ഈ ഉദാഹരണത്തിൽ:

ഫെച്ച്-ആസ്-യു-റെൻഡറിനായുള്ള ലൈബ്രറികൾ

ഒരു ശക്തമായ റിസോഴ്സ് മാനേജർ സ്വമേധയാ നിർമ്മിക്കുകയും പരിപാലിക്കുകയും ചെയ്യുന്നത് സങ്കീർണ്ണമാണ്. ഭാഗ്യവശാൽ, പക്വതയാർന്ന നിരവധി ഡാറ്റാ ഫെച്ചിംഗ് ലൈബ്രറികൾ സസ്പെൻസ് സ്വീകരിക്കുകയോ സ്വീകരിക്കുന്നുണ്ടോ ഉണ്ട്, അവ പരീക്ഷിച്ച് വിജയിച്ച പരിഹാരങ്ങൾ നൽകുന്നു:

ഈ ലൈബ്രറികൾ റിസോഴ്‌സുകൾ സൃഷ്‌ടിക്കുന്നതിനും നിയന്ത്രിക്കുന്നതിനും, കാഷിംഗ്, റീവാലിഡേഷൻ, ഒപ്റ്റിമിസ്റ്റിക് അപ്‌ഡേറ്റുകൾ, എറർ ഹാൻഡ്ലിംഗ് എന്നിവയുടെ സങ്കീർണ്ണതകൾ ലളിതമാക്കുന്നു, ഇത് ഫെച്ച്-ആസ്-യു-റെൻഡർ നടപ്പിലാക്കുന്നത് വളരെ എളുപ്പമാക്കുന്നു.

പാറ്റേൺ 4: സസ്പെൻസ്-അവയർ ലൈബ്രറികൾ ഉപയോഗിച്ച് പ്രീഫെച്ചിംഗ്

ഒരു ഉപയോക്താവിന് സമീപഭാവിയിൽ ആവശ്യമായി വരാനിരിക്കുന്ന ഡാറ്റ, അവർ വ്യക്തമായി അഭ്യർത്ഥിക്കുന്നതിന് മുമ്പുതന്നെ മുൻകൂട്ടി ഫെച്ച് ചെയ്യുന്ന ഒരു ശക്തമായ ഒപ്റ്റിമൈസേഷനാണ് പ്രീഫെച്ചിംഗ്. ഇത് പ്രകടനം ഗണ്യമായി മെച്ചപ്പെടുത്താൻ സഹായിക്കും.

സസ്പെൻസ്-അവയർ ലൈബ്രറികൾ ഉപയോഗിക്കുമ്പോൾ, പ്രീഫെച്ചിംഗ് തടസ്സമില്ലാത്തതായിത്തീരുന്നു. ഒരു ലിങ്കിന് മുകളിൽ ഹോവർ ചെയ്യുകയോ ഒരു ബട്ടണിന് മുകളിൽ മൗസ് കൊണ്ടുപോകുകയോ പോലുള്ള, യുഐയെ ഉടനടി മാറ്റാത്ത ഉപയോക്തൃ ഇടപെടലുകളിൽ നിങ്ങൾക്ക് ഡാറ്റാ ഫെച്ചുകൾ ട്രിഗർ ചെയ്യാൻ കഴിയും.

import React, { Suspense } from 'react';
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';

// ഇവ നിങ്ങളുടെ എപിഐ കോളുകളാണെന്ന് കരുതുക
const fetchProductById = async (id) => {
  console.log(`ഉൽപ്പന്നം ${id}-നെ ഫെച്ച് ചെയ്യുന്നു...`);
  return new Promise(resolve => setTimeout(() => {
    const products = {
      'A001': { id: 'A001', name: 'ഗ്ലോബൽ വിഡ്ജറ്റ് X', price: 29.99, description: 'അന്താരാഷ്ട്ര ഉപയോഗത്തിനായി ഒരു വൈവിധ്യമാർന്ന വിഡ്ജറ്റ്.' },
      'B002': { id: 'B002', name: 'യൂണിവേഴ്സൽ ഗാഡ്‌ജെറ്റ് Y', price: 149.99, description: 'അത്യാധുനിക ഗാഡ്‌ജെറ്റ്, ലോകമെമ്പാടും പ്രിയപ്പെട്ടത്.' },
    };
    resolve(products[id]);
  }, 1000));
};

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      suspense: true, // ഡിഫോൾട്ടായി എല്ലാ ക്വറികൾക്കും സസ്പെൻസ് പ്രവർത്തനക്ഷമമാക്കുക
    },
  },
});

function ProductDetails({ productId }) {
  const { data: product } = useQuery({
    queryKey: ['product', productId],
    queryFn: () => fetchProductById(productId),
  });

  return (
    <div style={{"border": "1px solid #ccc", "padding": "15px", "margin": "10px 0"}}>
      <h3>{product.name}</h3>
      <p>വില: ${product.price.toFixed(2)}</p>
      <p>{product.description}</p>
    </div>
  );
}

function ProductList() {
  const handleProductHover = (productId) => {
    // ഒരു ഉപയോക്താവ് ഉൽപ്പന്ന ലിങ്കിന് മുകളിൽ ഹോവർ ചെയ്യുമ്പോൾ ഡാറ്റ പ്രീഫെച്ച് ചെയ്യുക
    queryClient.prefetchQuery({
      queryKey: ['product', productId],
      queryFn: () => fetchProductById(productId),
    });
    console.log(`ഉൽപ്പന്നം ${productId}-നെ പ്രീഫെച്ച് ചെയ്യുന്നു`);
  };

  return (
    <div>
      <h2>ലഭ്യമായ ഉൽപ്പന്നങ്ങൾ:</h2>
      <ul>
        <li>
          <a href="#" onMouseEnter={() => handleProductHover('A001')}
             onClick={(e) => { e.preventDefault(); /* നാവിഗേറ്റ് ചെയ്യുക അല്ലെങ്കിൽ വിശദാംശങ്ങൾ കാണിക്കുക */ }}
          >ഗ്ലോബൽ വിഡ്ജറ്റ് X (A001)</a>
        </li>
        <li>
          <a href="#" onMouseEnter={() => handleProductHover('B002')}
             onClick={(e) => { e.preventDefault(); /* നാവിഗേറ്റ് ചെയ്യുക അല്ലെങ്കിൽ വിശദാംശങ്ങൾ കാണിക്കുക */ }}
          >യൂണിവേഴ്സൽ ഗാഡ്‌ജെറ്റ് Y (B002)</a>
        </li>
      </ul>
      <p>പ്രീഫെച്ചിംഗ് പ്രവർത്തനത്തിൽ കാണാൻ ഒരു ഉൽപ്പന്ന ലിങ്കിന് മുകളിൽ ഹോവർ ചെയ്യുക. നിരീക്ഷിക്കാൻ നെറ്റ്‌വർക്ക് ടാബ് തുറക്കുക.</p>
    </div>
  );
}

function App() {
  const [showProductA, setShowProductA] = React.useState(false);
  const [showProductB, setShowProductB] = React.useState(false);

  return (
    <QueryClientProvider client={queryClient}>
      <h1>റിയാക്ട് സസ്പെൻസ് ഉപയോഗിച്ചുള്ള പ്രീഫെച്ചിംഗ് (റിയാക്ട് ക്വറി)</h1>
      <ProductList />

      <button onClick={() => setShowProductA(true)}>ഗ്ലോബൽ വിഡ്ജറ്റ് X കാണിക്കുക</button>
      <button onClick={() => setShowProductB(true)}>യൂണിവേഴ്സൽ ഗാഡ്‌ജെറ്റ് Y കാണിക്കുക</button>

      {showProductA && (
        <Suspense fallback={<p>ഗ്ലോബൽ വിഡ്ജറ്റ് X ലോഡ് ചെയ്യുന്നു...</p>}>
          <ProductDetails productId="A001" />
        </Suspense>
      )}
      {showProductB && (
        <Suspense fallback={<p>യൂണിവേഴ്സൽ ഗാഡ്‌ജെറ്റ് Y ലോഡ് ചെയ്യുന്നു...</p>}>
          <ProductDetails productId="B002" />
        </Suspense>
      )}
    </QueryClientProvider>
  );
}

ഈ ഉദാഹരണത്തിൽ, ഒരു ഉൽപ്പന്ന ലിങ്കിന് മുകളിൽ ഹോവർ ചെയ്യുന്നത് `queryClient.prefetchQuery`-യെ ട്രിഗർ ചെയ്യുന്നു, ഇത് പശ്ചാത്തലത്തിൽ ഡാറ്റാ ഫെച്ച് ആരംഭിക്കുന്നു. ഉപയോക്താവ് ഉൽപ്പന്നത്തിൻ്റെ വിശദാംശങ്ങൾ കാണിക്കാൻ ബട്ടൺ ക്ലിക്കുചെയ്യുമ്പോൾ, പ്രീഫെച്ചിൽ നിന്ന് ഡാറ്റ ഇതിനകം കാഷെയിലുണ്ടെങ്കിൽ, കമ്പോണൻ്റ് സസ്പെൻഡ് ചെയ്യാതെ തൽക്ഷണം റെൻഡർ ചെയ്യും. പ്രീഫെച്ച് ഇപ്പോഴും പുരോഗമിക്കുകയാണെങ്കിലോ അല്ലെങ്കിൽ ആരംഭിച്ചിട്ടില്ലെങ്കിലോ, ഡാറ്റ തയ്യാറാകുന്നതുവരെ സസ്പെൻസ് ഫാൾബാക്ക് പ്രദർശിപ്പിക്കും.

സസ്പെൻസും എറർ ബൗണ്ടറീസും ഉപയോഗിച്ച് എറർ ഹാൻഡ്ലിംഗ്

സസ്പെൻസ് 'ലോഡിംഗ്' സ്റ്റേറ്റ് ഒരു ഫാൾബാക്ക് പ്രദർശിപ്പിച്ച് കൈകാര്യം ചെയ്യുമ്പോൾ, അത് നേരിട്ട് 'എറർ' സ്റ്റേറ്റുകൾ കൈകാര്യം ചെയ്യുന്നില്ല. ഒരു സസ്പെൻഡിംഗ് കമ്പോണൻ്റ് ത്രോ ചെയ്ത പ്രോമിസ് റിജക്ട് ആയാൽ (അതായത്, ഡാറ്റാ ഫെച്ചിംഗ് പരാജയപ്പെട്ടാൽ), ഈ എറർ കമ്പോണൻ്റ് ട്രീയിലൂടെ മുകളിലേക്ക് വ്യാപിക്കും. ഈ എററുകൾ ഭംഗിയായി കൈകാര്യം ചെയ്യാനും ഉചിതമായ യുഐ പ്രദർശിപ്പിക്കാനും, നിങ്ങൾ എറർ ബൗണ്ടറീസ് ഉപയോഗിക്കേണ്ടതുണ്ട്.

ഒരു എറർ ബൗണ്ടറി എന്നത് componentDidCatch അല്ലെങ്കിൽ static getDerivedStateFromError ലൈഫ്സൈക്കിൾ മെത്തേഡുകൾ നടപ്പിലാക്കുന്ന ഒരു റിയാക്ട് കമ്പോണൻ്റാണ്. ഇത് അതിൻ്റെ ചൈൽഡ് കമ്പോണൻ്റ് ട്രീയിലെവിടെയുമുള്ള ജാവാസ്ക്രിപ്റ്റ് എററുകളെ പിടിച്ചെടുക്കുന്നു, സസ്പെൻസ് പെൻഡിംഗ് ആയിരുന്നെങ്കിൽ സാധാരണയായി പിടിക്കുന്ന പ്രോമിസുകൾ ത്രോ ചെയ്യുന്ന എററുകൾ ഉൾപ്പെടെ.

import React, { Suspense, useState } from 'react';
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';

// --- എറർ ബൗണ്ടറി കമ്പോണൻ്റ് --- //
class MyErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error) {
    // അടുത്ത റെൻഡറിൽ ഫാൾബാക്ക് യുഐ കാണിക്കുന്നതിനായി സ്റ്റേറ്റ് അപ്ഡേറ്റ് ചെയ്യുക.
    return { hasError: true, error };
  }

  componentDidCatch(error, errorInfo) {
    // നിങ്ങൾക്ക് ഒരു എറർ റിപ്പോർട്ടിംഗ് സേവനത്തിലേക്ക് എറർ ലോഗ് ചെയ്യാനും കഴിയും
    console.error("ഒരു പിശക് പിടികൂടി:", error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // നിങ്ങൾക്ക് ഏത് കസ്റ്റം ഫാൾബാക്ക് യുഐയും റെൻഡർ ചെയ്യാം
      return (
        <div style={{"border": "2px solid red", "padding": "20px", "margin": "20px 0", "background": "#ffe0e0"}}>
          <h2>എന്തോ പിശക് സംഭവിച്ചു!</h2>
          <p>{this.state.error && this.state.error.message}</p>
          <p>ദയവായി പേജ് റീഫ്രഷ് ചെയ്യുക അല്ലെങ്കിൽ സപ്പോർട്ടുമായി ബന്ധപ്പെടുക.</p>
          <button onClick={() => this.setState({ hasError: false, error: null })}>വീണ്ടും ശ്രമിക്കുക</button>
        </div>
      );
    }
    return this.props.children;
  }
}

// --- ഡാറ്റാ ഫെച്ചിംഗ് (പിശകിന് സാധ്യതയുള്ളത്) --- //
const fetchItemById = async (id) => {
  console.log(`ഐറ്റം ${id} ഫെച്ച് ചെയ്യാൻ ശ്രമിക്കുന്നു...`);
  return new Promise((resolve, reject) => setTimeout(() => {
    if (id === 'error-item') {
      reject(new Error('ഐറ്റം ലോഡ് ചെയ്യുന്നതിൽ പരാജയപ്പെട്ടു: നെറ്റ്‌വർക്ക് ലഭ്യമല്ല അല്ലെങ്കിൽ ഐറ്റം കണ്ടെത്തിയില്ല.'));
    } else if (id === 'slow-item') {
      resolve({ id: 'slow-item', name: 'പതുക്കെ ഡെലിവർ ചെയ്തത്', data: 'ഈ ഐറ്റം കുറച്ച് സമയമെടുത്തു, പക്ഷേ എത്തി!', status: 'success' });
    } else {
      resolve({ id, name: `ഐറ്റം ${id}`, data: `ഐറ്റം ${id}-നുള്ള ഡാറ്റ` });
    }
  }, id === 'slow-item' ? 3000 : 800));
};

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      suspense: true,
      retry: false, // പ്രദർശനത്തിനായി, റീട്രൈ പ്രവർത്തനരഹിതമാക്കുക, അങ്ങനെ പിശക് ഉടനടി ഉണ്ടാകും
    },
  },
});

function DisplayItem({ itemId }) {
  const { data: item } = useQuery({
    queryKey: ['item', itemId],
    queryFn: () => fetchItemById(itemId),
  });

  return (
    <div>
      <h3>ഐറ്റം വിശദാംശങ്ങൾ:</h3>
      <p>ഐഡി: {item.id}</p>
      <p>പേര്: {item.name}</p>
      <p>ഡാറ്റ: {item.data}</p>
    </div>
  );
}

function App() {
  const [fetchType, setFetchType] = useState('normal-item');

  return (
    <QueryClientProvider client={queryClient}>
      <h1>സസ്പെൻസും എറർ ബൗണ്ടറീസും</h1>

      <div>
        <button onClick={() => setFetchType('normal-item')}>സാധാരണ ഐറ്റം ഫെച്ച് ചെയ്യുക</button>
        <button onClick={() => setFetchType('slow-item')}>വേഗത കുറഞ്ഞ ഐറ്റം ഫെച്ച് ചെയ്യുക</button>
        <button onClick={() => setFetchType('error-item')}>എറർ ഐറ്റം ഫെച്ച് ചെയ്യുക</button>
      </div>

      <MyErrorBoundary>
        <Suspense fallback={<p>സസ്പെൻസ് വഴി ഐറ്റം ലോഡ് ചെയ്യുന്നു...</p>}>
          <DisplayItem itemId={fetchType} />
        </Suspense>
      </MyErrorBoundary>
    </QueryClientProvider>
  );
}

നിങ്ങളുടെ സസ്പെൻസ് ബൗണ്ടറിയെ (അല്ലെങ്കിൽ സസ്പെൻഡ് ചെയ്യാൻ സാധ്യതയുള്ള കമ്പോണൻ്റുകളെ) ഒരു എറർ ബൗണ്ടറി ഉപയോഗിച്ച് പൊതിയുന്നതിലൂടെ, ഡാറ്റാ ഫെച്ചിംഗ് സമയത്ത് ഉണ്ടാകുന്ന നെറ്റ്‌വർക്ക് പരാജയങ്ങളോ സെർവർ എററുകളോ പിടികൂടി ഭംഗിയായി കൈകാര്യം ചെയ്യുന്നുവെന്ന് ഉറപ്പാക്കാം, ഇത് മുഴുവൻ ആപ്ലിക്കേഷനും ക്രാഷാകുന്നത് തടയുന്നു. ഇത് ശക്തവും ഉപയോക്തൃ-സൗഹൃദവുമായ അനുഭവം നൽകുന്നു, ഉപയോക്താക്കൾക്ക് പ്രശ്നം മനസ്സിലാക്കാനും വീണ്ടും ശ്രമിക്കാനും അവസരം നൽകുന്നു.

സസ്പെൻസ് ഉപയോഗിച്ച് സ്റ്റേറ്റ് മാനേജ്മെൻ്റും ഡാറ്റ ഇൻവാലിഡേഷനും

റിയാക്ട് സസ്പെൻസ് പ്രധാനമായും അസിൻക്രണസ് റിസോഴ്‌സുകളുടെ പ്രാരംഭ ലോഡിംഗ് സ്റ്റേറ്റിനെയാണ് അഭിസംബോധന ചെയ്യുന്നത് എന്ന് വ്യക്തമാക്കേണ്ടത് പ്രധാനമാണ്. ഇത് ക്ലയിൻ്റ്-സൈഡ് കാഷെ കൈകാര്യം ചെയ്യുകയോ, ഡാറ്റ ഇൻവാലിഡേഷൻ കൈകാര്യം ചെയ്യുകയോ, മ്യൂട്ടേഷനുകൾ (ക്രിയേറ്റ്, അപ്ഡേറ്റ്, ഡിലീറ്റ് ഓപ്പറേഷനുകൾ) ഏകോപിപ്പിക്കുകയോ, അവയുടെ തുടർന്നുള്ള യുഐ അപ്‌ഡേറ്റുകൾ നടത്തുകയോ ചെയ്യുന്നില്ല.

ഇവിടെയാണ് സസ്പെൻസ്-അവയർ ഡാറ്റാ ഫെച്ചിംഗ് ലൈബ്രറികൾ (റിയാക്ട് ക്വറി, SWR, അപ്പോളോ ക്ലയിൻ്റ്, റിലേ) ഒഴിച്ചുകൂടാനാവാത്തതായി മാറുന്നത്. അവ സസ്പെൻസിനെ പൂർത്തീകരിക്കുന്നത് ഇങ്ങനെയാണ്:

ഒരു ശക്തമായ ഡാറ്റാ ഫെച്ചിംഗ് ലൈബ്രറിയില്ലാതെ, ഒരു മാനുവൽ സസ്പെൻസ് റിസോഴ്സ് മാനേജറിന് മുകളിൽ ഈ ഫീച്ചറുകൾ നടപ്പിലാക്കുന്നത് ഒരു വലിയ സംരംഭമായിരിക്കും, അടിസ്ഥാനപരമായി നിങ്ങളുടെ സ്വന്തം ഡാറ്റാ ഫെച്ചിംഗ് ഫ്രെയിംവർക്ക് നിർമ്മിക്കേണ്ടതുണ്ട്.

പ്രായോഗിക പരിഗണനകളും മികച്ച രീതികളും

ഡാറ്റാ ഫെച്ചിംഗിനായി സസ്പെൻസ് സ്വീകരിക്കുന്നത് ഒരു സുപ്രധാന ആർക്കിടെക്ചറൽ തീരുമാനമാണ്. ഒരു ഗ്ലോബൽ ആപ്ലിക്കേഷനായുള്ള ചില പ്രായോഗിക പരിഗണനകൾ ഇതാ:

1. എല്ലാ ഡാറ്റയ്ക്കും സസ്പെൻസ് ആവശ്യമില്ല

ഒരു കമ്പോണൻ്റിൻ്റെ പ്രാരംഭ റെൻഡറിംഗിനെ നേരിട്ട് ബാധിക്കുന്ന നിർണ്ണായക ഡാറ്റയ്ക്ക് സസ്പെൻസ് അനുയോജ്യമാണ്. നിർണ്ണായകമല്ലാത്ത ഡാറ്റ, പശ്ചാത്തല ഫെച്ചുകൾ, അല്ലെങ്കിൽ ശക്തമായ ദൃശ്യപരമായ സ്വാധീനമില്ലാതെ അലസമായി ലോഡ് ചെയ്യാൻ കഴിയുന്ന ഡാറ്റ എന്നിവയ്ക്ക്, പരമ്പരാഗത useEffect അല്ലെങ്കിൽ പ്രീ-റെൻഡറിംഗ് ഇപ്പോഴും അനുയോജ്യമായേക്കാം. സസ്പെൻസിൻ്റെ അമിതമായ ഉപയോഗം ഒരു കുറഞ്ഞ ഗ്രാനുലാർ ലോഡിംഗ് അനുഭവത്തിലേക്ക് നയിച്ചേക്കാം, കാരണം ഒരു സസ്പെൻസ് ബൗണ്ടറി അതിൻ്റെ *എല്ലാ* ചിൽഡ്രനും റിസോൾവ് ചെയ്യുന്നതുവരെ കാത്തിരിക്കുന്നു.

2. സസ്പെൻസ് ബൗണ്ടറികളുടെ ഗ്രാനുലാരിറ്റി

നിങ്ങളുടെ <Suspense> ബൗണ്ടറികൾ ചിന്താപൂർവ്വം സ്ഥാപിക്കുക. നിങ്ങളുടെ ആപ്ലിക്കേഷൻ്റെ മുകളിലുള്ള ഒരൊറ്റ, വലിയ ബൗണ്ടറി മുഴുവൻ പേജിനെയും ഒരു സ്പിന്നറിന് പിന്നിൽ മറച്ചേക്കാം, ഇത് നിരാശാജനകമാണ്. ചെറുതും കൂടുതൽ ഗ്രാനുലാറുമായ ബൗണ്ടറികൾ നിങ്ങളുടെ പേജിൻ്റെ വിവിധ ഭാഗങ്ങൾ സ്വതന്ത്രമായി ലോഡ് ചെയ്യാൻ അനുവദിക്കുന്നു, ഇത് കൂടുതൽ പുരോഗമനപരവും പ്രതികരണശേഷിയുള്ളതുമായ അനുഭവം നൽകുന്നു. ഉദാഹരണത്തിന്, ഒരു ഉപയോക്തൃ പ്രൊഫൈൽ കമ്പോണൻ്റിന് ചുറ്റും ഒരു ബൗണ്ടറിയും, ശുപാർശ ചെയ്യുന്ന ഉൽപ്പന്നങ്ങളുടെ ഒരു ലിസ്റ്റിന് ചുറ്റും മറ്റൊന്നും.

<div>
  <h1>ഉൽപ്പന്ന പേജ്</h1>
  <Suspense fallback={<p>പ്രധാന ഉൽപ്പന്ന വിശദാംശങ്ങൾ ലോഡ് ചെയ്യുന്നു...</p>}>
    <ProductDetails id="prod123" />
  </Suspense>

  <hr />

  <h2>ബന്ധപ്പെട്ട ഉൽപ്പന്നങ്ങൾ</h2>
  <Suspense fallback={<p>ബന്ധപ്പെട്ട ഉൽപ്പന്നങ്ങൾ ലോഡ് ചെയ്യുന്നു...</p>}>
    <RelatedProducts category="electronics" />
  </Suspense>
</div>

ഈ സമീപനം അർത്ഥമാക്കുന്നത് ബന്ധപ്പെട്ട ഉൽപ്പന്നങ്ങൾ ഇപ്പോഴും ലോഡ് ചെയ്യുകയാണെങ്കിലും ഉപയോക്താക്കൾക്ക് പ്രധാന ഉൽപ്പന്ന വിശദാംശങ്ങൾ കാണാൻ കഴിയും എന്നാണ്.

3. സെർവർ-സൈഡ് റെൻഡറിംഗ് (SSR), സ്ട്രീമിംഗ് HTML

റിയാക്ട് 18-ൻ്റെ പുതിയ സ്ട്രീമിംഗ് SSR എപിഐകൾ (renderToPipeableStream) സസ്പെൻസുമായി പൂർണ്ണമായി സംയോജിക്കുന്നു. പേജിൻ്റെ ഭാഗങ്ങൾ (ഡാറ്റയെ ആശ്രയിക്കുന്ന കമ്പോണൻ്റുകൾ പോലുള്ളവ) ഇപ്പോഴും ലോഡ് ചെയ്യുകയാണെങ്കിലും, നിങ്ങളുടെ സെർവറിന് HTML തയ്യാറായാലുടൻ അയയ്ക്കാൻ ഇത് അനുവദിക്കുന്നു. സെർവറിന് ഒരു പ്ലേസ്ഹോൾഡർ (സസ്പെൻസ് ഫാൾബാക്കിൽ നിന്ന്) സ്ട്രീം ചെയ്യാനും ഡാറ്റ റിസോൾവ് ചെയ്യുമ്പോൾ യഥാർത്ഥ ഉള്ളടക്കം സ്ട്രീം ചെയ്യാനും കഴിയും, ഒരു പൂർണ്ണ ക്ലയിൻ്റ്-സൈഡ് റീ-റെൻഡർ ആവശ്യമില്ലാതെ. ഇത് വ്യത്യസ്ത നെറ്റ്‌വർക്ക് സാഹചര്യങ്ങളിലുള്ള ആഗോള ഉപയോക്താക്കൾക്ക് ലോഡിംഗ് പ്രകടനം ഗണ്യമായി മെച്ചപ്പെടുത്തുന്നു.

4. ഘട്ടം ഘട്ടമായുള്ള സ്വീകരണം

സസ്പെൻസ് ഉപയോഗിക്കുന്നതിന് നിങ്ങളുടെ മുഴുവൻ ആപ്ലിക്കേഷനും മാറ്റിയെഴുതേണ്ടതില്ല. അതിൻ്റെ ഡിക്ലറേറ്റീവ് ലോഡിംഗ് പാറ്റേണുകളിൽ നിന്ന് ഏറ്റവും കൂടുതൽ പ്രയോജനം ലഭിക്കുന്ന പുതിയ ഫീച്ചറുകളിലോ കമ്പോണൻ്റുകളിലോ തുടങ്ങി നിങ്ങൾക്ക് ഇത് ഘട്ടം ഘട്ടമായി അവതരിപ്പിക്കാം.

5. ടൂളിംഗും ഡീബഗ്ഗിംഗും

സസ്പെൻസ് കമ്പോണൻ്റ് ലോജിക് ലളിതമാക്കുമ്പോൾ, ഡീബഗ്ഗിംഗ് വ്യത്യസ്തമായിരിക്കും. റിയാക്ട് ഡെവലപ്പർ ടൂളുകൾ സസ്പെൻസ് ബൗണ്ടറികളെയും അവയുടെ സ്റ്റേറ്റുകളെയും കുറിച്ചുള്ള ഉൾക്കാഴ്ചകൾ നൽകുന്നു. നിങ്ങൾ തിരഞ്ഞെടുത്ത ഡാറ്റാ ഫെച്ചിംഗ് ലൈബ്രറി അതിൻ്റെ ആന്തരിക സ്റ്റേറ്റ് എങ്ങനെ വെളിപ്പെടുത്തുന്നു എന്നതിനെക്കുറിച്ച് സ്വയം പരിചയപ്പെടുക (ഉദാ., റിയാക്ട് ക്വറി ഡെവലപ്പർ ടൂളുകൾ).

6. സസ്പെൻസ് ഫാൾബാക്കുകൾക്കുള്ള ടൈംഔട്ടുകൾ

വളരെ ദൈർഘ്യമേറിയ ലോഡിംഗ് സമയങ്ങൾക്കായി, നിങ്ങളുടെ സസ്പെൻസ് ഫാൾബാക്കിലേക്ക് ഒരു ടൈംഔട്ട് അവതരിപ്പിക്കാൻ നിങ്ങൾ ആഗ്രഹിച്ചേക്കാം, അല്ലെങ്കിൽ ഒരു നിശ്ചിത കാലതാമസത്തിന് ശേഷം കൂടുതൽ വിശദമായ ഒരു ലോഡിംഗ് ഇൻഡിക്കേറ്ററിലേക്ക് മാറുക. റിയാക്ട് 18-ലെ useDeferredValue, useTransition ഹുക്കുകൾ ഈ കൂടുതൽ സൂക്ഷ്മമായ ലോഡിംഗ് സ്റ്റേറ്റുകൾ കൈകാര്യം ചെയ്യാൻ സഹായിക്കും, പുതിയ ഡാറ്റ ഫെച്ച് ചെയ്യുമ്പോൾ യുഐയുടെ 'പഴയ' പതിപ്പ് കാണിക്കാനോ അടിയന്തിരമല്ലാത്ത അപ്‌ഡേറ്റുകൾ മാറ്റിവയ്ക്കാനോ നിങ്ങളെ അനുവദിക്കുന്നു.

റിയാക്ടിലെ ഡാറ്റാ ഫെച്ചിംഗിൻ്റെ ഭാവി: റിയാക്ട് സെർവർ കമ്പോണൻ്റുകളും അതിനപ്പുറവും

റിയാക്ടിലെ ഡാറ്റാ ഫെച്ചിംഗിൻ്റെ യാത്ര ക്ലയിൻ്റ്-സൈഡ് സസ്പെൻസിൽ അവസാനിക്കുന്നില്ല. റിയാക്ട് സെർവർ കമ്പോണൻ്റുകൾ (RSC) ഒരു സുപ്രധാന പരിണാമത്തെ പ്രതിനിധീകരിക്കുന്നു, ക്ലയിൻ്റും സെർവറും തമ്മിലുള്ള അതിരുകൾ മങ്ങിക്കുമെന്നും ഡാറ്റാ ഫെച്ചിംഗ് കൂടുതൽ ഒപ്റ്റിമൈസ് ചെയ്യുമെന്നും വാഗ്ദാനം ചെയ്യുന്നു.

റിയാക്ട് പക്വത പ്രാപിക്കുന്നത് തുടരുമ്പോൾ, ഉയർന്ന പ്രകടനശേഷിയുള്ളതും ഉപയോക്തൃ-സൗഹൃദവും പരിപാലിക്കാൻ എളുപ്പമുള്ളതുമായ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്നതിനുള്ള പസിലിൻ്റെ ഒരു പ്രധാന ഭാഗമായിരിക്കും സസ്പെൻസ്. ഇത് ഡെവലപ്പർമാരെ അസിൻക്രണസ് പ്രവർത്തനങ്ങൾ കൈകാര്യം ചെയ്യുന്നതിനുള്ള കൂടുതൽ ഡിക്ലറേറ്റീവും പ്രതിരോധശേഷിയുള്ളതുമായ ഒരു മാർഗ്ഗത്തിലേക്ക് നയിക്കുന്നു, സങ്കീർണ്ണത വ്യക്തിഗത കമ്പോണൻ്റുകളിൽ നിന്ന് നന്നായി കൈകാര്യം ചെയ്യുന്ന ഒരു ഡാറ്റാ ലെയറിലേക്ക് മാറ്റുന്നു.

ഉപസംഹാരം

റിയാക്ട് സസ്പെൻസ്, തുടക്കത്തിൽ കോഡ് സ്പ്ലിറ്റിംഗിനായുള്ള ഒരു ഫീച്ചർ, ഡാറ്റാ ഫെച്ചിംഗിനുള്ള ഒരു പരിവർത്തനാത്മക ഉപകരണമായി മാറിയിരിക്കുന്നു. ഫെച്ച്-ആസ്-യു-റെൻഡർ പാറ്റേൺ സ്വീകരിക്കുന്നതിലൂടെയും സസ്പെൻസ്-അവയർ ലൈബ്രറികൾ ഉപയോഗിക്കുന്നതിലൂടെയും, ഡെവലപ്പർമാർക്ക് അവരുടെ ആപ്ലിക്കേഷനുകളുടെ ഉപയോക്തൃ അനുഭവം ഗണ്യമായി മെച്ചപ്പെടുത്താൻ കഴിയും, ലോഡിംഗ് വാട്ടർഫാളുകൾ ഇല്ലാതാക്കുകയും, കമ്പോണൻ്റ് ലോജിക് ലളിതമാക്കുകയും, സുഗമവും ഏകോപിതവുമായ ലോഡിംഗ് സ്റ്റേറ്റുകൾ നൽകുകയും ചെയ്യുന്നു. ശക്തമായ എറർ ഹാൻഡ്ലിംഗിനായി എറർ ബൗണ്ടറികളും റിയാക്ട് സെർവർ കമ്പോണൻ്റുകളുടെ ഭാവി വാഗ്ദാനവും കൂടിച്ചേരുമ്പോൾ, പ്രകടനക്ഷമവും പ്രതിരോധശേഷിയുള്ളതും മാത്രമല്ല, ലോകമെമ്പാടുമുള്ള ഉപയോക്താക്കൾക്ക് സ്വാഭാവികമായും കൂടുതൽ ആനന്ദകരവുമായ ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കാൻ സസ്പെൻസ് നമ്മെ പ്രാപ്തരാക്കുന്നു. സസ്പെൻസ്-ഡ്രിവൺ ഡാറ്റാ ഫെച്ചിംഗ് മാതൃകയിലേക്കുള്ള മാറ്റത്തിന് ഒരു ആശയപരമായ ക്രമീകരണം ആവശ്യമാണ്, എന്നാൽ കോഡ് വ്യക്തത, പ്രകടനം, ഉപയോക്തൃ സംതൃപ്തി എന്നിവയുടെ കാര്യത്തിലുള്ള പ്രയോജനങ്ങൾ ഗണ്യമായതും നിക്ഷേപത്തിന് അർഹവുമാണ്.