റിയാക്റ്റിന്റെ റീകൺസിലിയേഷൻ പ്രക്രിയയിൽ വൈദഗ്ദ്ധ്യം നേടൂ. 'key' പ്രോപ്പ് ശരിയായി ഉപയോഗിക്കുന്നത് ലിസ്റ്റ് റെൻഡറിംഗ് എങ്ങനെ മെച്ചപ്പെടുത്തുന്നു, ബഗുകൾ തടയുന്നു, ആപ്ലിക്കേഷൻ പ്രകടനം വർദ്ധിപ്പിക്കുന്നു എന്ന് പഠിക്കുക. ആഗോള ഡെവലപ്പർമാർക്കുള്ള ഒരു വഴികാട്ടി.
പ്രകടനം മെച്ചപ്പെടുത്താം: ലിസ്റ്റ് ഒപ്റ്റിമൈസേഷനായി റിയാക്റ്റ് റീകൺസിലിയേഷൻ കീകളെക്കുറിച്ചുള്ള ആഴത്തിലുള്ള പഠനം
ആധുനിക വെബ് ഡെവലപ്മെന്റിന്റെ ലോകത്ത്, ഡാറ്റാ മാറ്റങ്ങളോട് വേഗത്തിൽ പ്രതികരിക്കുന്ന ഡൈനാമിക് യൂസർ ഇന്റർഫേസുകൾ നിർമ്മിക്കുന്നത് വളരെ പ്രധാനമാണ്. റിയാക്റ്റ്, അതിന്റെ കമ്പോണന്റ്-ബേസ്ഡ് ആർക്കിടെക്ചറും ഡിക്ലറേറ്റീവ് സ്വഭാവവും കൊണ്ട്, ഈ ഇന്റർഫേസുകൾ നിർമ്മിക്കുന്നതിനുള്ള ഒരു ആഗോള നിലവാരമായി മാറിയിരിക്കുന്നു. റിയാക്റ്റിന്റെ കാര്യക്ഷമതയുടെ ഹൃദയഭാഗത്ത് റീകൺസിലിയേഷൻ എന്നറിയപ്പെടുന്ന ഒരു പ്രക്രിയയാണ്, അതിൽ വെർച്വൽ ഡോം (Virtual DOM) ഉൾപ്പെടുന്നു. എന്നിരുന്നാലും, ഏറ്റവും ശക്തമായ ടൂളുകൾ പോലും കാര്യക്ഷമമല്ലാത്ത രീതിയിൽ ഉപയോഗിക്കാം, പുതിയതും പരിചയസമ്പന്നരുമായ ഡെവലപ്പർമാർ ഒരുപോലെ ഇടറുന്ന ഒരു സാധാരണ മേഖലയാണ് ലിസ്റ്റുകളുടെ റെൻഡറിംഗ്.
നിങ്ങൾ മിക്കവാറും data.map(item => <div>{item.name}</div>)
പോലുള്ള കോഡ് പലതവണ എഴുതിയിട്ടുണ്ടാകും. ഇത് ലളിതവും നിസ്സാരവുമാണെന്ന് തോന്നാം. എന്നിരുന്നാലും, ഈ ലാളിത്യത്തിന് താഴെ ഒരു നിർണ്ണായക പ്രകടന പരിഗണനയുണ്ട്, അത് അവഗണിച്ചാൽ, മന്ദഗതിയിലുള്ള ആപ്ലിക്കേഷനുകളിലേക്കും ആശയക്കുഴപ്പമുണ്ടാക്കുന്ന ബഗുകളിലേക്കും നയിച്ചേക്കാം. ഇതിന്റെ പരിഹാരമോ? ചെറുതും എന്നാൽ ശക്തവുമായ ഒരു പ്രോപ്പ്: key
.
ഈ സമഗ്രമായ ഗൈഡ് നിങ്ങളെ റിയാക്റ്റിന്റെ റീകൺസിലിയേഷൻ പ്രക്രിയയിലേക്കും ലിസ്റ്റ് റെൻഡറിംഗിൽ 'കീ'കളുടെ ഒഴിച്ചുകൂടാനാവാത്ത പങ്കിനെക്കുറിച്ചുമുള്ള ആഴത്തിലുള്ള പഠനത്തിലേക്ക് കൊണ്ടുപോകും. നമ്മൾ 'എന്ത്' എന്ന് മാത്രമല്ല, 'എന്തുകൊണ്ട്' എന്നും പര്യവേക്ഷണം ചെയ്യും - എന്തുകൊണ്ടാണ് കീകൾ അത്യാവശ്യമായത്, അവ എങ്ങനെ ശരിയായി തിരഞ്ഞെടുക്കാം, തെറ്റായി ഉപയോഗിക്കുന്നതിന്റെ കാര്യമായ പ്രത്യാഘാതങ്ങൾ എന്തൊക്കെയാണ്. ഇത് അവസാനിക്കുമ്പോഴേക്കും, കൂടുതൽ മികച്ചതും സ്ഥിരതയുള്ളതും പ്രൊഫഷണലുമായ റിയാക്റ്റ് ആപ്ലിക്കേഷനുകൾ എഴുതാനുള്ള അറിവ് നിങ്ങൾക്ക് ലഭിക്കും.
അദ്ധ്യായം 1: റിയാക്റ്റിന്റെ റീകൺസിലിയേഷനും വെർച്വൽ ഡോമും മനസ്സിലാക്കൽ
'കീ'കളുടെ പ്രാധാന്യം മനസ്സിലാക്കുന്നതിന് മുമ്പ്, റിയാക്റ്റിനെ വേഗതയുള്ളതാക്കുന്ന അടിസ്ഥാന സംവിധാനം നമ്മൾ ആദ്യം മനസ്സിലാക്കണം: വെർച്വൽ ഡോം (VDOM) നൽകുന്ന റീകൺസിലിയേഷൻ.
എന്താണ് വെർച്വൽ ഡോം?
ബ്രൗസറിന്റെ ഡോക്യുമെന്റ് ഒബ്ജക്റ്റ് മോഡലുമായി (DOM) നേരിട്ട് ഇടപെടുന്നത് കമ്പ്യൂട്ടേഷണലായി ചെലവേറിയതാണ്. നിങ്ങൾ ഡോമിൽ എന്തെങ്കിലും മാറ്റം വരുത്തുമ്പോഴെല്ലാം - ഒരു നോഡ് ചേർക്കുക, ടെക്സ്റ്റ് അപ്ഡേറ്റ് ചെയ്യുക, അല്ലെങ്കിൽ ഒരു സ്റ്റൈൽ മാറ്റുക - ബ്രൗസറിന് കാര്യമായ അളവിലുള്ള ജോലി ചെയ്യേണ്ടിവരും. ഇതിന് പേജിന്റെ മുഴുവൻ സ്റ്റൈലുകളും ലേഔട്ടും പുനഃക്രമീകരിക്കേണ്ടി വന്നേക്കാം, ഈ പ്രക്രിയയെ റിഫ്ലോ, റീപെയിന്റ് എന്ന് പറയുന്നു. സങ്കീർണ്ണവും ഡാറ്റാ-ഡ്രിവൺ ആയതുമായ ഒരു ആപ്ലിക്കേഷനിൽ, അടിക്കടിയുള്ള നേരിട്ടുള്ള ഡോം മാനിപ്പുലേഷനുകൾ പ്രകടനത്തെ പെട്ടെന്ന് മന്ദഗതിയിലാക്കും.
ഈ പ്രശ്നം പരിഹരിക്കാൻ റിയാക്റ്റ് ഒരു അബ്സ്ട്രാക്ഷൻ ലെയർ അവതരിപ്പിക്കുന്നു: വെർച്വൽ ഡോം. വിഡോം എന്നത് യഥാർത്ഥ ഡോമിന്റെ ഭാരം കുറഞ്ഞ, ഇൻ-മെമ്മറിയിലുള്ള ഒരു പ്രാതിനിധ്യമാണ്. ഇത് നിങ്ങളുടെ യുഐയുടെ ഒരു ബ്ലൂപ്രിന്റ് ആയി കരുതുക. നിങ്ങൾ റിയാക്റ്റിനോട് യുഐ അപ്ഡേറ്റ് ചെയ്യാൻ പറയുമ്പോൾ (ഉദാഹരണത്തിന്, ഒരു കമ്പോണന്റിന്റെ സ്റ്റേറ്റ് മാറ്റുന്നതിലൂടെ), റിയാക്റ്റ് ഉടൻ തന്നെ യഥാർത്ഥ ഡോമിൽ തൊടുന്നില്ല. പകരം, അത് താഴെപ്പറയുന്ന ഘട്ടങ്ങൾ ചെയ്യുന്നു:
- അപ്ഡേറ്റ് ചെയ്ത സ്റ്റേറ്റിനെ പ്രതിനിധീകരിക്കുന്ന ഒരു പുതിയ വിഡോം ട്രീ സൃഷ്ടിക്കപ്പെടുന്നു.
- ഈ പുതിയ വിഡോം ട്രീയെ മുൻപത്തെ വിഡോം ട്രീയുമായി താരതമ്യം ചെയ്യുന്നു. ഈ താരതമ്യ പ്രക്രിയയെ "ഡിഫിംഗ്" എന്ന് വിളിക്കുന്നു.
- പഴയ വിഡോമിനെ പുതിയതിലേക്ക് മാറ്റാൻ ആവശ്യമായ ഏറ്റവും കുറഞ്ഞ മാറ്റങ്ങൾ റിയാക്റ്റ് കണ്ടെത്തുന്നു.
- ഈ കുറഞ്ഞ മാറ്റങ്ങൾ ഒരുമിച്ച് ചേർത്ത് ഒരൊറ്റ, കാര്യക്ഷമമായ പ്രവർത്തനത്തിലൂടെ യഥാർത്ഥ ഡോമിൽ പ്രയോഗിക്കുന്നു.
റീകൺസിലിയേഷൻ എന്നറിയപ്പെടുന്ന ഈ പ്രക്രിയയാണ് റിയാക്റ്റിനെ ഇത്രയധികം കാര്യക്ഷമമാക്കുന്നത്. മുഴുവൻ വീടും പുനർനിർമ്മിക്കുന്നതിനുപകരം, ഏത് ഇഷ്ടികകളാണ് മാറ്റേണ്ടതെന്ന് കൃത്യമായി തിരിച്ചറിയുന്ന ഒരു വിദഗ്ദ്ധനായ കോൺട്രാക്ടറെപ്പോലെ റിയാക്റ്റ് പ്രവർത്തിക്കുന്നു, അതുവഴി ജോലിയും തടസ്സങ്ങളും കുറയ്ക്കുന്നു.
അദ്ധ്യായം 2: കീകൾ ഇല്ലാതെ ലിസ്റ്റുകൾ റെൻഡർ ചെയ്യുമ്പോഴുള്ള പ്രശ്നം
ഇനി, ഈ മികച്ച സംവിധാനത്തിന് എവിടെയാണ് പ്രശ്നങ്ങൾ നേരിടാൻ കഴിയുന്നതെന്ന് നോക്കാം. ഉപയോക്താക്കളുടെ ഒരു ലിസ്റ്റ് റെൻഡർ ചെയ്യുന്ന ലളിതമായ ഒരു കമ്പോണന്റ് പരിഗണിക്കുക:
function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li>{user.name}</li>
))}
</ul>
);
}
ഈ കമ്പോണന്റ് ആദ്യമായി റെൻഡർ ചെയ്യുമ്പോൾ, റിയാക്റ്റ് ഒരു വിഡോം ട്രീ നിർമ്മിക്കുന്നു. നമ്മൾ `users` അറേയുടെ *അവസാനം* ഒരു പുതിയ ഉപയോക്താവിനെ ചേർത്താൽ, റിയാക്റ്റിന്റെ ഡിഫിംഗ് അൽഗോരിതം അത് ഭംഗിയായി കൈകാര്യം ചെയ്യും. ഇത് പഴയതും പുതിയതുമായ ലിസ്റ്റുകളെ താരതമ്യം ചെയ്യുകയും അവസാനം ഒരു പുതിയ ഐറ്റം കാണുകയും യഥാർത്ഥ ഡോമിലേക്ക് ഒരു പുതിയ `<li>` ചേർക്കുകയും ചെയ്യുന്നു. കാര്യക്ഷമവും ലളിതവും.
എന്നാൽ നമ്മൾ ലിസ്റ്റിന്റെ തുടക്കത്തിൽ ഒരു പുതിയ ഉപയോക്താവിനെ ചേർത്താലോ, അല്ലെങ്കിൽ ഐറ്റംസ് പുനഃക്രമീകരിച്ചാലോ എന്ത് സംഭവിക്കും?
നമ്മുടെ പ്രാരംഭ ലിസ്റ്റ് ഇതാണെന്ന് കരുതുക:
- Alice
- Bob
ഒരു അപ്ഡേറ്റിന് ശേഷം അത് ഇങ്ങനെയാകുന്നു:
- Charlie
- Alice
- Bob
പ്രത്യേക ഐഡന്റിഫയറുകൾ ഇല്ലാതെ, റിയാക്റ്റ് രണ്ട് ലിസ്റ്റുകളെയും അവയുടെ ക്രമം (ഇൻഡെക്സ്) അടിസ്ഥാനമാക്കി താരതമ്യം ചെയ്യുന്നു. അത് കാണുന്നത് ഇതാ:
- സ്ഥാനം 0: പഴയ ഐറ്റം "Alice" ആയിരുന്നു. പുതിയ ഐറ്റം "Charlie" ആണ്. റിയാക്റ്റ് ഈ സ്ഥാനത്തുള്ള കമ്പോണന്റ് അപ്ഡേറ്റ് ചെയ്യേണ്ടതുണ്ടെന്ന് നിഗമനം ചെയ്യുന്നു. നിലവിലുള്ള ഡോം നോഡിന്റെ ഉള്ളടക്കം "Alice" എന്നതിൽ നിന്ന് "Charlie" എന്നാക്കി മാറ്റുന്നു.
- സ്ഥാനം 1: പഴയ ഐറ്റം "Bob" ആയിരുന്നു. പുതിയ ഐറ്റം "Alice" ആണ്. റിയാക്റ്റ് രണ്ടാമത്തെ ഡോം നോഡിന്റെ ഉള്ളടക്കം "Bob" എന്നതിൽ നിന്ന് "Alice" എന്നാക്കി മാറ്റുന്നു.
- സ്ഥാനം 2: മുമ്പ് ഇവിടെ ഐറ്റം ഉണ്ടായിരുന്നില്ല. പുതിയ ഐറ്റം "Bob" ആണ്. റിയാക്റ്റ് "Bob" നായി ഒരു പുതിയ ഡോം നോഡ് സൃഷ്ടിച്ച് ചേർക്കുന്നു.
ഇത് അങ്ങേയറ്റം കാര്യക്ഷമമല്ലാത്ത ഒന്നാണ്. തുടക്കത്തിൽ "Charlie" ക്കായി ഒരു പുതിയ എലമെന്റ് ചേർക്കുന്നതിന് പകരം, റിയാക്റ്റ് രണ്ട് മ്യൂട്ടേഷനുകളും ഒരു ഇൻസെർഷനും നടത്തി. ഒരു വലിയ ലിസ്റ്റിനോ, അല്ലെങ്കിൽ സ്വന്തമായി സ്റ്റേറ്റ് ഉള്ള സങ്കീർണ്ണമായ ലിസ്റ്റ് ഐറ്റംസിനോ, ഈ അനാവശ്യ ജോലി കാര്യമായ പ്രകടനത്തകർച്ചയ്ക്കും, അതിലും പ്രധാനമായി, കമ്പോണന്റ് സ്റ്റേറ്റുമായി ബന്ധപ്പെട്ട ബഗുകൾക്കും കാരണമാകും.
ഇതുകൊണ്ടാണ്, നിങ്ങൾ മുകളിലുള്ള കോഡ് പ്രവർത്തിപ്പിച്ചാൽ, നിങ്ങളുടെ ബ്രൗസറിന്റെ ഡെവലപ്പർ കൺസോളിൽ ഒരു മുന്നറിയിപ്പ് കാണിക്കുന്നത്: "Warning: Each child in a list should have a unique 'key' prop." റിയാക്റ്റ് അതിന്റെ ജോലി കാര്യക്ഷമമായി ചെയ്യാൻ സഹായം ആവശ്യമാണെന്ന് വ്യക്തമായി നിങ്ങളോട് പറയുകയാണ്.
അദ്ധ്യായം 3: രക്ഷകനായി `key` പ്രോപ്പ്
റിയാക്റ്റിന് ആവശ്യമായ സൂചനയാണ് `key` പ്രോപ്പ്. എലമെന്റുകളുടെ ലിസ്റ്റുകൾ നിർമ്മിക്കുമ്പോൾ നിങ്ങൾ നൽകുന്ന ഒരു പ്രത്യേക സ്ട്രിംഗ് ആട്രിബ്യൂട്ടാണിത്. കീകൾ ഓരോ എലമെന്റിനും റീ-റെൻഡറുകളിലുടനീളം സ്ഥിരവും അതുല്യവുമായ ഒരു ഐഡന്റിറ്റി നൽകുന്നു.
നമ്മുടെ `UserList` കമ്പോണന്റ് 'കീകൾ' ഉപയോഗിച്ച് മാറ്റിയെഴുതാം:
function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
ഇവിടെ, ഓരോ `user` ഒബ്ജക്റ്റിനും ഒരു തനതായ `id` പ്രോപ്പർട്ടി ഉണ്ടെന്ന് നമ്മൾ അനുമാനിക്കുന്നു (ഉദാഹരണത്തിന്, ഒരു ഡാറ്റാബേസിൽ നിന്ന്). ഇനി നമ്മുടെ സാഹചര്യം വീണ്ടും പരിശോധിക്കാം.
പ്രാരംഭ ഡാറ്റ:
[{ id: 'u1', name: 'Alice' }, { id: 'u2', name: 'Bob' }]
അപ്ഡേറ്റ് ചെയ്ത ഡാറ്റ:
[{ id: 'u3', name: 'Charlie' }, { id: 'u1', name: 'Alice' }, { id: 'u2', name: 'Bob' }]
'കീകൾ' ഉപയോഗിച്ച്, റിയാക്റ്റിന്റെ ഡിഫിംഗ് പ്രക്രിയ വളരെ മികച്ചതാണ്:
- റിയാക്റ്റ് പുതിയ വിഡോമിലെ `<ul>` ന്റെ ചിൽഡ്രനുകളെ നോക്കുകയും അവയുടെ കീകൾ പരിശോധിക്കുകയും ചെയ്യുന്നു. അത് `u3`, `u1`, `u2` എന്നിവ കാണുന്നു.
- തുടർന്ന് അത് മുൻപത്തെ വിഡോമിന്റെ ചിൽഡ്രനുകളെയും അവയുടെ കീകളെയും പരിശോധിക്കുന്നു. അത് `u1`, `u2` എന്നിവ കാണുന്നു.
- റിയാക്റ്റിന് അറിയാം `u1`, `u2` എന്നീ കീകൾ ഉള്ള കമ്പോണന്റുകൾ ഇതിനകം നിലവിലുണ്ടെന്ന്. അവയെ മാറ്റം വരുത്തേണ്ട ആവശ്യമില്ല; അവയുടെ ഡോം നോഡുകൾ പുതിയ സ്ഥാനങ്ങളിലേക്ക് നീക്കിയാൽ മതി.
- `u3` എന്ന കീ പുതിയതാണെന്ന് റിയാക്റ്റ് കാണുന്നു. അത് "Charlie" ക്കായി ഒരു പുതിയ കമ്പോണന്റും ഡോം നോഡും ഉണ്ടാക്കി തുടക്കത്തിൽ ചേർക്കുന്നു.
ഇതിന്റെ ഫലം ഒരൊറ്റ ഡോം ഇൻസെർഷനും കുറച്ച് പുനഃക്രമീകരണവുമാണ്, ഇത് നമ്മൾ മുമ്പ് കണ്ട ഒന്നിലധികം മ്യൂട്ടേഷനുകളെയും ഇൻസെർഷനെയുംക്കാൾ വളരെ കാര്യക്ഷമമാണ്. കീകൾ ഒരു സ്ഥിരമായ ഐഡന്റിറ്റി നൽകുന്നു, ഇത് റിയാക്റ്റിനെ അറേയിലെ സ്ഥാനത്തെ പരിഗണിക്കാതെ തന്നെ റെൻഡറുകളിലുടനീളം എലമെന്റുകളെ ട്രാക്ക് ചെയ്യാൻ അനുവദിക്കുന്നു.
അദ്ധ്യായം 4: ശരിയായ കീ തിരഞ്ഞെടുക്കൽ - സുവർണ്ണ നിയമങ്ങൾ
`key` പ്രോപ്പിന്റെ ഫലപ്രാപ്തി പൂർണ്ണമായും ശരിയായ മൂല്യം തിരഞ്ഞെടുക്കുന്നതിനെ ആശ്രയിച്ചിരിക്കുന്നു. അറിഞ്ഞിരിക്കേണ്ട വ്യക്തമായ മികച്ച സമ്പ്രദായങ്ങളും അപകടകരമായ ആന്റി-പാറ്റേണുകളും ഉണ്ട്.
ഏറ്റവും മികച്ച കീ: അതുല്യവും സ്ഥിരവുമായ ഐഡികൾ
ഒരു ലിസ്റ്റിനുള്ളിൽ ഒരു ഐറ്റത്തെ അതുല്യമായും സ്ഥിരമായും തിരിച്ചറിയുന്ന ഒരു മൂല്യമാണ് അനുയോജ്യമായ കീ. ഇത് മിക്കവാറും എല്ലായ്പ്പോഴും നിങ്ങളുടെ ഡാറ്റാ ഉറവിടത്തിൽ നിന്നുള്ള ഒരു തനതായ ഐഡി ആയിരിക്കും.
- അത് അതിന്റെ സഹോദരങ്ങൾക്കിടയിൽ (siblings) അതുല്യമായിരിക്കണം. കീകൾ ആഗോളമായി അതുല്യമാകേണ്ടതില്ല, ആ തലത്തിൽ റെൻഡർ ചെയ്യുന്ന എലമെന്റുകളുടെ ലിസ്റ്റിനുള്ളിൽ മാത്രം അതുല്യമായാൽ മതി. ഒരേ പേജിലെ രണ്ട് വ്യത്യസ്ത ലിസ്റ്റുകളിലെ ഐറ്റംസിന് ഒരേ കീ ഉണ്ടാകാം.
- അത് സ്ഥിരമായിരിക്കണം. ഒരു പ്രത്യേക ഡാറ്റാ ഐറ്റത്തിനുള്ള കീ റെൻഡറുകൾക്കിടയിൽ മാറരുത്. നിങ്ങൾ ആലീസിന്റെ ഡാറ്റ വീണ്ടും ഫെച്ച് ചെയ്യുകയാണെങ്കിൽ, അവൾക്ക് ഇപ്പോഴും അതേ `id` തന്നെയായിരിക്കണം.
കീകൾക്കുള്ള മികച്ച ഉറവിടങ്ങൾ ഉൾപ്പെടുന്നു:
- ഡാറ്റാബേസ് പ്രൈമറി കീകൾ (ഉദാ. `user.id`, `product.sku`)
- യൂണിവേഴ്സലി യൂണീക്ക് ഐഡന്റിഫയറുകൾ (UUIDs)
- നിങ്ങളുടെ ഡാറ്റയിൽ നിന്നുള്ള മാറ്റമില്ലാത്ത, അതുല്യമായ ഒരു സ്ട്രിംഗ് (ഉദാ. ഒരു പുസ്തകത്തിന്റെ ISBN)
// നല്ലത്: ഡാറ്റയിൽ നിന്ന് സ്ഥിരവും അതുല്യവുമായ ഒരു ഐഡി ഉപയോഗിക്കുന്നു.
<div>
{products.map(product => (
<ProductItem key={product.sku} product={product} />
))}
</div>
ആന്റി-പാറ്റേൺ: അറേ ഇൻഡെക്സ് കീ ആയി ഉപയോഗിക്കുന്നത്
ഒരു സാധാരണ തെറ്റാണ് അറേ ഇൻഡെക്സ് ഒരു കീ ആയി ഉപയോഗിക്കുന്നത്:
// മോശം: അറേ ഇൻഡെക്സ് ഒരു കീ ആയി ഉപയോഗിക്കുന്നു.
<div>
{items.map((item, index) => (
<ListItem key={index} item={item} />
))}
</div>
ഇത് റിയാക്റ്റ് മുന്നറിയിപ്പ് നിശബ്ദമാക്കുമെങ്കിലും, ഇത് ഗുരുതരമായ പ്രശ്നങ്ങളിലേക്ക് നയിച്ചേക്കാം, സാധാരണയായി ഇതൊരു ആന്റി-പാറ്റേൺ ആയി കണക്കാക്കപ്പെടുന്നു. ഇൻഡെക്സ് ഒരു കീ ആയി ഉപയോഗിക്കുന്നത് ഒരു ഐറ്റത്തിന്റെ ഐഡന്റിറ്റി അതിന്റെ ലിസ്റ്റിലെ സ്ഥാനവുമായി ബന്ധിപ്പിച്ചിരിക്കുന്നു എന്ന് റിയാക്റ്റിനോട് പറയുന്നു. ലിസ്റ്റ് പുനഃക്രമീകരിക്കപ്പെടുമ്പോഴോ, ഫിൽട്ടർ ചെയ്യുമ്പോഴോ, തുടക്കത്തിൽ നിന്നോ മധ്യത്തിൽ നിന്നോ ഐറ്റംസ് ചേർക്കുകയോ നീക്കം ചെയ്യുകയോ ചെയ്യുമ്പോൾ കീ ഇല്ലാത്ത അതേ പ്രശ്നം തന്നെയാണ് ഇതിനും.
സ്റ്റേറ്റ് മാനേജ്മെന്റ് ബഗ്:
നിങ്ങളുടെ ലിസ്റ്റ് ഐറ്റംസ് അവയുടെ സ്വന്തം സ്റ്റേറ്റ് മാനേജ് ചെയ്യുമ്പോൾ ഇൻഡെക്സ് കീകൾ ഉപയോഗിക്കുന്നതിന്റെ ഏറ്റവും അപകടകരമായ പാർശ്വഫലം പ്രത്യക്ഷപ്പെടുന്നു. ഇൻപുട്ട് ഫീൽഡുകളുടെ ഒരു ലിസ്റ്റ് സങ്കൽപ്പിക്കുക:
function UnstableList() {
const [items, setItems] = React.useState([{ id: 1, text: 'First' }, { id: 2, text: 'Second' }]);
const handleAddItemToTop = () => {
setItems([{ id: 3, text: 'New Top' }, ...items]);
};
return (
<div>
<button onClick={handleAddItemToTop}>Add to Top</button>
{items.map((item, index) => (
<div key={index}>
<label>{item.text}: </label>
<input type="text" />
</div>
))}
</div>
);
}
ഈ മാനസിക വ്യായാമം പരീക്ഷിക്കുക:
- ലിസ്റ്റ് "First", "Second" എന്നിവയുമായി റെൻഡർ ചെയ്യുന്നു.
- നിങ്ങൾ ആദ്യത്തെ ഇൻപുട്ട് ഫീൽഡിൽ ("First" നുള്ളത്) "Hello" എന്ന് ടൈപ്പ് ചെയ്യുന്നു.
- നിങ്ങൾ "Add to Top" ബട്ടണിൽ ക്ലിക്കുചെയ്യുന്നു.
എന്ത് സംഭവിക്കുമെന്നാണ് നിങ്ങൾ പ്രതീക്ഷിക്കുന്നത്? "New Top" നായി ഒരു പുതിയ, ശൂന്യമായ ഇൻപുട്ട് പ്രത്യക്ഷപ്പെടുമെന്നും, "First" നുള്ള ഇൻപുട്ട് ("Hello" അടങ്ങിയത്) താഴേക്ക് നീങ്ങുമെന്നും നിങ്ങൾ പ്രതീക്ഷിക്കും. എന്നാൽ യഥാർത്ഥത്തിൽ എന്ത് സംഭവിക്കുന്നു? ആദ്യത്തെ സ്ഥാനത്തുള്ള (ഇൻഡെക്സ് 0) ഇൻപുട്ട് ഫീൽഡ്, അതിൽ ഇപ്പോഴും "Hello" ഉണ്ട്, അവിടെത്തന്നെ നിലനിൽക്കുന്നു. എന്നാൽ ഇപ്പോൾ അത് പുതിയ ഡാറ്റാ ഐറ്റം ആയ "New Top" മായി ബന്ധപ്പെട്ടിരിക്കുന്നു. ഇൻപുട്ട് കമ്പോണന്റിന്റെ സ്റ്റേറ്റ് (അതിന്റെ ആന്തരിക മൂല്യം) അത് പ്രതിനിധീകരിക്കേണ്ട ഡാറ്റയുമായിട്ടല്ല, മറിച്ച് അതിന്റെ സ്ഥാനവുമായി (കീ=0) ബന്ധിപ്പിച്ചിരിക്കുന്നു. ഇൻഡെക്സ് കീകൾ മൂലമുണ്ടാകുന്ന ഒരു ക്ലാസിക്, ആശയക്കുഴപ്പമുണ്ടാക്കുന്ന ബഗ് ആണിത്.
നിങ്ങൾ `key={index}` എന്നത് `key={item.id}` എന്നാക്കി മാറ്റിയാൽ മാത്രം മതി, പ്രശ്നം പരിഹരിക്കപ്പെടും. റിയാക്റ്റ് ഇപ്പോൾ കമ്പോണന്റിന്റെ സ്റ്റേറ്റിനെ ഡാറ്റയുടെ സ്ഥിരമായ ഐഡിയുമായി ശരിയായി ബന്ധിപ്പിക്കും.
എപ്പോഴാണ് ഒരു ഇൻഡെക്സ് കീ ഉപയോഗിക്കാൻ കഴിയുന്നത്?
ഇൻഡെക്സ് ഉപയോഗിക്കുന്നത് സുരക്ഷിതമായ അപൂർവ്വം സാഹചര്യങ്ങളുണ്ട്, എന്നാൽ നിങ്ങൾ ഈ വ്യവസ്ഥകളെല്ലാം പാലിക്കണം:
- ലിസ്റ്റ് സ്റ്റാറ്റിക് ആണ്: അത് ഒരിക്കലും പുനഃക്രമീകരിക്കുകയോ, ഫിൽട്ടർ ചെയ്യുകയോ, അവസാനം ഒഴികെ എവിടെനിന്നും ഐറ്റംസ് ചേർക്കുകയോ നീക്കം ചെയ്യുകയോ ചെയ്യില്ല.
- ലിസ്റ്റിലെ ഐറ്റംസിന് സ്ഥിരമായ ഐഡികൾ ഇല്ല.
- ഓരോ ഐറ്റത്തിനും വേണ്ടി റെൻഡർ ചെയ്ത കമ്പോണന്റുകൾ ലളിതവും ആന്തരിക സ്റ്റേറ്റ് ഇല്ലാത്തവയുമാണ്.
അപ്പോഴും, സാധ്യമെങ്കിൽ ഒരു താൽക്കാലികവും എന്നാൽ സ്ഥിരവുമായ ഐഡി ഉണ്ടാക്കുന്നതാണ് നല്ലത്. ഇൻഡെക്സ് ഉപയോഗിക്കുന്നത് എല്ലായ്പ്പോഴും ഒരു ബോധപൂർവമായ തീരുമാനമായിരിക്കണം, അല്ലാതെ സ്ഥിരമായി ചെയ്യുന്ന ഒന്നായിരിക്കരുത്.
ഏറ്റവും മോശം കുറ്റവാളി: `Math.random()`
ഒരിക്കലും `Math.random()` അല്ലെങ്കിൽ മറ്റേതെങ്കിലും നോൺ-ഡിറ്റർമിനിസ്റ്റിക് മൂല്യം കീ ആയി ഉപയോഗിക്കരുത്:
// വളരെ മോശം: ഇത് ചെയ്യരുത്!
<div>
{items.map(item => (
<ListItem key={Math.random()} item={item} />
))}
</div>
`Math.random()` ഉപയോഗിച്ച് ഉണ്ടാക്കുന്ന ഒരു കീ ഓരോ റെൻഡറിലും വ്യത്യസ്തമായിരിക്കുമെന്ന് ഉറപ്പാണ്. ഇത് റിയാക്റ്റിനോട് പറയുന്നത് മുൻപത്തെ റെൻഡറിലെ മുഴുവൻ കമ്പോണന്റുകളും നശിപ്പിക്കപ്പെട്ടു എന്നും തികച്ചും വ്യത്യസ്തമായ പുതിയൊരു ലിസ്റ്റ് ഉണ്ടാക്കിയെന്നും ആണ്. ഇത് എല്ലാ പഴയ കമ്പോണന്റുകളെയും അൺമൗണ്ട് ചെയ്യാനും (അവയുടെ സ്റ്റേറ്റ് നശിപ്പിക്കാനും) എല്ലാ പുതിയവയെയും മൗണ്ട് ചെയ്യാനും റിയാക്റ്റിനെ നിർബന്ധിതരാക്കുന്നു. ഇത് റീകൺസിലിയേഷന്റെ ഉദ്ദേശ്യത്തെ പൂർണ്ണമായും പരാജയപ്പെടുത്തുകയും പ്രകടനത്തിന് ഏറ്റവും മോശം ഓപ്ഷനുമാണ്.
അദ്ധ്യായം 5: വിപുലമായ ആശയങ്ങളും പൊതുവായ ചോദ്യങ്ങളും
കീകളും `React.Fragment`-ഉം
ചിലപ്പോൾ ഒരു `map` കോൾബാക്കിൽ നിന്ന് ഒന്നിലധികം എലമെന്റുകൾ റിട്ടേൺ ചെയ്യേണ്ടി വരും. ഇതിന്റെ സാധാരണ മാർഗ്ഗം `React.Fragment` ഉപയോഗിക്കുക എന്നതാണ്. നിങ്ങൾ ഇത് ചെയ്യുമ്പോൾ, `key` എന്നത് `Fragment` കമ്പോണന്റിൽ തന്നെ വെക്കണം.
function Glossary({ terms }) {
return (
<dl>
{terms.map(term => (
// കീ Fragment-ൽ ആണ് വെക്കേണ്ടത്, ചിൽഡ്രനിലല്ല.
<React.Fragment key={term.id}>
<dt>{term.name}</dt>
<dd>{term.definition}</dd>
</React.Fragment>
))}
</dl>
);
}
പ്രധാനപ്പെട്ടത്: ഷോർട്ട്ഹാൻഡ് സിന്റാക്സ് ആയ `<>...</>` കീകൾ പിന്തുണയ്ക്കുന്നില്ല. നിങ്ങളുടെ ലിസ്റ്റിന് ഫ്രാഗ്മെന്റുകൾ ആവശ്യമാണെങ്കിൽ, നിങ്ങൾ `<React.Fragment>` എന്ന സിന്റാക്സ് തന്നെ ഉപയോഗിക്കണം.
കീകൾ സഹോദരങ്ങൾക്കിടയിൽ മാത്രം അതുല്യമായാൽ മതി
കീകൾ നിങ്ങളുടെ മുഴുവൻ ആപ്ലിക്കേഷനിലും ആഗോളമായി അതുല്യമായിരിക്കണം എന്നത് ഒരു സാധാരണ തെറ്റിദ്ധാരണയാണ്. ഇത് ശരിയല്ല. ഒരു കീ അതിന്റെ തൊട്ടടുത്ത സഹോദരങ്ങളുടെ ലിസ്റ്റിനുള്ളിൽ മാത്രം അതുല്യമായാൽ മതി.
function CourseRoster({ courses }) {
return (
<div>
{courses.map(course => (
<div key={course.id}> {/* കോഴ്സിനുള്ള കീ */}
<h3>{course.title}</h3>
<ul>
{course.students.map(student => (
// ഈ സ്റ്റുഡന്റ് കീ ഈ കോഴ്സിന്റെ സ്റ്റുഡന്റ് ലിസ്റ്റിനുള്ളിൽ മാത്രം അതുല്യമായാൽ മതി.
<li key={student.id}>{student.name}</li>
))}
</ul>
</div>
))}
</div>
);
}
മുകളിലെ ഉദാഹരണത്തിൽ, രണ്ട് വ്യത്യസ്ത കോഴ്സുകൾക്ക് `id: 's1'` ഉള്ള ഒരു വിദ്യാർത്ഥി ഉണ്ടാകാം. ഇത് തികച്ചും ശരിയാണ്, കാരണം കീകൾ വ്യത്യസ്ത പാരന്റ് `<ul>` എലമെന്റുകൾക്കുള്ളിലാണ് വിലയിരുത്തപ്പെടുന്നത്.
കമ്പോണന്റ് സ്റ്റേറ്റ് മനഃപൂർവ്വം റീസെറ്റ് ചെയ്യാൻ കീകൾ ഉപയോഗിക്കുന്നത്
കീകൾ പ്രധാനമായും ലിസ്റ്റ് ഒപ്റ്റിമൈസേഷന് വേണ്ടിയുള്ളതാണെങ്കിലും, അവയ്ക്ക് ആഴത്തിലുള്ള ഒരു ഉദ്ദേശ്യമുണ്ട്: അവ ഒരു കമ്പോണന്റിന്റെ ഐഡന്റിറ്റി നിർവചിക്കുന്നു. ഒരു കമ്പോണന്റിന്റെ കീ മാറുകയാണെങ്കിൽ, റിയാക്റ്റ് നിലവിലുള്ള കമ്പോണന്റിനെ അപ്ഡേറ്റ് ചെയ്യാൻ ശ്രമിക്കില്ല. പകരം, അത് പഴയ കമ്പോണന്റിനെയും (അതിന്റെ എല്ലാ ചിൽഡ്രനെയും) നശിപ്പിച്ച് ആദ്യം മുതൽ ഒരു പുതിയൊരെണ്ണം ഉണ്ടാക്കും. ഇത് പഴയ ഇൻസ്റ്റൻസിനെ അൺമൗണ്ട് ചെയ്യുകയും ഒരു പുതിയതിനെ മൗണ്ട് ചെയ്യുകയും ചെയ്യുന്നു, ഫലപ്രദമായി അതിന്റെ സ്റ്റേറ്റ് റീസെറ്റ് ചെയ്യുന്നു.
ഒരു കമ്പോണന്റിനെ റീസെറ്റ് ചെയ്യാൻ ഇത് ശക്തവും ഡിക്ലറേറ്റീവുമായ ഒരു മാർഗ്ഗമാണ്. ഉദാഹരണത്തിന്, ഒരു `userId` അടിസ്ഥാനമാക്കി ഡാറ്റ ഫെച്ച് ചെയ്യുന്ന ഒരു `UserProfile` കമ്പോണന്റ് സങ്കൽപ്പിക്കുക.
function App() {
const [userId, setUserId] = React.useState('user-1');
return (
<div>
<button onClick={() => setUserId('user-1')}>View User 1</button>
<button onClick={() => setUserId('user-2')}>View User 2</button>
<UserProfile key={userId} id={userId} />
</div>
);
}
`UserProfile` കമ്പോണന്റിൽ `key={userId}` വെക്കുന്നതിലൂടെ, `userId` മാറുമ്പോഴെല്ലാം മുഴുവൻ `UserProfile` കമ്പോണന്റും ഉപേക്ഷിച്ച് ഒരു പുതിയൊരെണ്ണം ഉണ്ടാക്കുമെന്ന് നമ്മൾ ഉറപ്പാക്കുന്നു. മുൻ ഉപയോക്താവിന്റെ പ്രൊഫൈലിൽ നിന്നുള്ള സ്റ്റേറ്റ് (ഫോം ഡാറ്റ അല്ലെങ്കിൽ ഫെച്ച് ചെയ്ത ഉള്ളടക്കം പോലുള്ളവ) നിലനിൽക്കാൻ സാധ്യതയുള്ള ബഗുകളെ ഇത് തടയുന്നു. കമ്പോണന്റ് ഐഡന്റിറ്റിയും ലൈഫ് സൈക്കിളും കൈകാര്യം ചെയ്യുന്നതിനുള്ള വൃത്തിയുള്ളതും വ്യക്തവുമായ ഒരു മാർഗ്ഗമാണിത്.
ഉപസംഹാരം: മികച്ച റിയാക്റ്റ് കോഡ് എഴുതുന്നു
`key` പ്രോപ്പ് ഒരു കൺസോൾ മുന്നറിയിപ്പ് നിശബ്ദമാക്കാനുള്ള ഒരു മാർഗ്ഗത്തേക്കാൾ വളരെ വലുതാണ്. ഇത് റിയാക്റ്റിനുള്ള ഒരു അടിസ്ഥാന നിർദ്ദേശമാണ്, അതിന്റെ റീകൺസിലിയേഷൻ അൽഗോരിതം കാര്യക്ഷമമായും ശരിയായും പ്രവർത്തിക്കാൻ ആവശ്യമായ നിർണായക വിവരങ്ങൾ നൽകുന്നു. 'കീ'കളുടെ ഉപയോഗത്തിൽ വൈദഗ്ദ്ധ്യം നേടുന്നത് ഒരു പ്രൊഫഷണൽ റിയാക്റ്റ് ഡെവലപ്പറുടെ അടയാളമാണ്.
പ്രധാന കാര്യങ്ങൾ സംഗ്രഹിക്കാം:
- പ്രകടനത്തിന് കീകൾ അത്യാവശ്യമാണ്: അവ റിയാക്റ്റിന്റെ ഡിഫിംഗ് അൽഗോരിതത്തെ അനാവശ്യ ഡോം മ്യൂട്ടേഷനുകൾ ഇല്ലാതെ ഒരു ലിസ്റ്റിലെ എലമെന്റുകളെ കാര്യക്ഷമമായി ചേർക്കാനും നീക്കം ചെയ്യാനും പുനഃക്രമീകരിക്കാനും സഹായിക്കുന്നു.
- എല്ലായ്പ്പോഴും സ്ഥിരവും അതുല്യവുമായ ഐഡികൾ ഉപയോഗിക്കുക: റെൻഡറുകളിലുടനീളം മാറ്റമില്ലാത്ത, നിങ്ങളുടെ ഡാറ്റയിൽ നിന്നുള്ള ഒരു തനതായ ഐഡന്റിഫയറാണ് ഏറ്റവും മികച്ച കീ.
- അറേ ഇൻഡെക്സുകൾ കീകൾ ആയി ഒഴിവാക്കുക: ഒരു ഐറ്റത്തിന്റെ ഇൻഡെക്സ് അതിന്റെ കീ ആയി ഉപയോഗിക്കുന്നത് മോശം പ്രകടനത്തിനും, സൂക്ഷ്മവും നിരാശാജനകവുമായ സ്റ്റേറ്റ് മാനേജ്മെന്റ് ബഗുകൾക്കും ഇടയാക്കും, പ്രത്യേകിച്ച് ഡൈനാമിക് ലിസ്റ്റുകളിൽ.
- ഒരിക്കലും റാൻഡം അല്ലെങ്കിൽ അസ്ഥിരമായ കീകൾ ഉപയോഗിക്കരുത്: ഇത് ഏറ്റവും മോശം സാഹചര്യമാണ്, കാരണം ഇത് ഓരോ റെൻഡറിലും മുഴുവൻ ലിസ്റ്റ് കമ്പോണന്റുകളെയും പുനർനിർമ്മിക്കാൻ റിയാക്റ്റിനെ നിർബന്ധിതരാക്കുന്നു, പ്രകടനത്തെയും സ്റ്റേറ്റിനെയും നശിപ്പിക്കുന്നു.
- കീകൾ കമ്പോണന്റ് ഐഡന്റിറ്റി നിർവചിക്കുന്നു: ഒരു കമ്പോണന്റിന്റെ കീ മാറ്റുന്നതിലൂടെ അതിന്റെ സ്റ്റേറ്റ് മനഃപൂർവ്വം റീസെറ്റ് ചെയ്യാൻ നിങ്ങൾക്ക് ഈ സ്വഭാവം ഉപയോഗിക്കാം.
ഈ തത്വങ്ങൾ ഉൾക്കൊള്ളുന്നതിലൂടെ, നിങ്ങൾ വേഗതയേറിയതും കൂടുതൽ വിശ്വസനീയവുമായ റിയാക്റ്റ് ആപ്ലിക്കേഷനുകൾ എഴുതുക മാത്രമല്ല, ലൈബ്രറിയുടെ പ്രധാന മെക്കാനിക്സുകളെക്കുറിച്ച് ആഴത്തിലുള്ള ധാരണ നേടുകയും ചെയ്യും. അടുത്ത തവണ നിങ്ങൾ ഒരു ലിസ്റ്റ് റെൻഡർ ചെയ്യാൻ ഒരു അറേയിൽ മാപ്പ് ചെയ്യുമ്പോൾ, `key` പ്രോപ്പിന് അത് അർഹിക്കുന്ന ശ്രദ്ധ നൽകുക. നിങ്ങളുടെ ആപ്ലിക്കേഷന്റെ പ്രകടനം - നിങ്ങളുടെ ഭാവിയിലെ നിങ്ങൾ തന്നെയും - അതിന് നിങ്ങളോട് നന്ദി പറയും.