چگونه می توانید React را متقاعد کنید که دو استفاده از یک کامپوننت به حالت جداگانه خود نیاز دارند؟ البته با کلید!
رویکرد React میتواند بسیار پیچیده باشد و ممکن است با رفتارهای غیرمنتظره یا حتی باگهای ظریف مواجه شوید. اگر با علت آنها آشنا نباشید، خلاص شدن از شر چنین اشکالاتی می تواند بسیار سخت باشد.
یک اشکال خاص زمانی ایجاد می شود که شما به صورت مشروط یک مؤلفه را با ویژگی های مختلف ارائه دهید. این باگ را با جزئیات بررسی کنید و نحوه استفاده از کلیدهای React را برای حل آن بیابید.
React Components همیشه مستقل نیستند
سینتکس ساده آن یکی از دلایل اصلی یادگیری React است. اما، با وجود مزایای بسیار، این چارچوب بدون اشکال نیست.
اشکالی که در اینجا با آن آشنا میشوید زمانی رخ میدهد که شما به صورت مشروط یک مؤلفه را رندر میکنید، اما آن را به صورت پایههای متفاوت ارسال میکنید.
در مواردی مانند این، React فرض میکند که دو مؤلفه یکسان هستند، بنابراین رندر مؤلفه دوم را به زحمت نمیاندازد. در نتیجه، هر حالتی که در کامپوننت اول تعریف کنید، بین رندرها باقی می ماند.
برای نشان دادن، این مثال را در نظر بگیرید. ابتدا مولفه شمارنده زیر را دارید:
import { useState, useEffect } from "react"
export function Counter({name}) {
const [count, setCount] = useState(0)
return(
<div>
<div>{name}</div>
<button onClick={() => setCount(c => c - 1)}> - </button>
<br />
<button onClick={() => setCount(c => c + 1)}> + </button>
</div>
)
}
این کامپوننت Counter یک نام از والد را از طریق تخریب شیء می پذیرد، که راهی برای استفاده از props در React است. سپس نام را در یک
در نظر داشته باشید که کد بالا مشکلی ندارد. این اشکال از بلوک کد زیر (جزء برنامه) می آید که از شمارنده استفاده می کند:
import { useState } from "react"
import { Counter } from "./Counter"
export default function App() {
const [isKingsley, setIsKingsley] = useState(true)
return(
<div>
{ isKingsley ? <Counter name="Kingsley" /> : <Counter name="Sally" /> }
<br />
<button onClick={() => setIsKingsley(k => !k)}> Swap </button>
</div>
)
}
به طور پیش فرض، کد بالا شمارنده را با نام Kingsley نمایش می دهد. اگر شمارنده را به پنج افزایش دهید و روی دکمه Swap کلیک کنید، شمارنده دوم به نام سالی نمایش داده می شود.
اما مشکل این است که شمارنده پس از تعویض آنها به حالت پیش فرض صفر خود بازنشانی نمی شود.
این اشکال به این دلیل رخ می دهد که هر دو حالت عناصر یکسان را به ترتیب یکسان ارائه می کنند. React نمی داند که شمارنده «کینگزلی» با شمارنده «سالی» متفاوت است. تنها تفاوت در نام پایه است، اما متاسفانه، React از آن برای متمایز کردن عناصر استفاده نمی کند.
از دو طریق می توانید این مشکل را برطرف کنید. اولین مورد با تغییر DOM و متفاوت کردن دو درخت است. این مستلزم آن است که شما بفهمید DOM چیست. به عنوان مثال، می توانید اولین شمارنده را در یک عنصر
import { useState } from "react"
import { Counter } from "./Counter"
export default function App() {
const [isKingsley, setIsKingsley] = useState(true)
return (
<div>
{ isKingsley ?
(<div>
<Counter name="Kingsley" />
</div>)
:
(<section>
<Counter name="Sally" />
</section>)
}
<br />
<button onClick={() => setIsKingsley(k => !k)}> Swap </button>
</div>
)
}
اگر شمارنده “Kingsley” را افزایش دهید و روی Swap کلیک کنید، وضعیت به 0 بازنشانی می شود. باز هم، این اتفاق می افتد زیرا ساختار دو درخت DOM متفاوت است.
وقتی متغیر isKingsley درست باشد، ساختار به صورت div > div > شمارنده (div حاوی div، حاوی شمارنده) خواهد بود. هنگامی که با استفاده از دکمه حالت شمارنده را تعویض می کنید، ساختار به div > بخش > شمارنده تبدیل می شود. به دلیل این اختلاف، React به طور خودکار یک شمارنده جدید را با وضعیت بازنشانی ارائه می کند.
ممکن است همیشه نخواهید ساختار نشانه گذاری خود را به این شکل تغییر دهید. راه دوم برای رفع این اشکال از نیاز به نشانه گذاری های مختلف جلوگیری می کند.
استفاده از کلیدها برای ارائه یک کامپوننت تازه
کلیدها به React اجازه میدهند تا بین عناصر در طول فرآیند رندر تفاوت قائل شود. بنابراین اگر دو عنصر دارید که دقیقاً یکسان هستند و می خواهید به React سیگنال دهید که یکی با دیگری متفاوت است، باید یک ویژگی کلیدی منحصر به فرد برای هر عنصر تنظیم کنید.
به هر شمارنده یک کلید اضافه کنید، مانند:
import { useState } from "react"
import { Counter } from "./Counter"
export default function App() {
const [isKingsley, setIsKingsley] = useState(true)
return(
<div>
{ isKingsley ?
<Counter key="Kingsley" name="Kingsley" /> :
<Counter key="Sally" name="Sally" />
}
<br />
<button onClick={() => setIsKingsley(k => !k)}> Swap </button>
</div>
)
}
اکنون، وقتی شمارنده «کینگزلی» را افزایش میدهید و روی Swap کلیک میکنید، React یک شمارنده جدید ارائه میکند و حالت را به صفر بازنشانی میکند.
هنگامی که آرایه ای از موارد مشابه را ارائه می کنید، باید از کلیدها استفاده کنید، زیرا React تفاوت بین هر مورد را نمی داند.
export default function App() {
const names = ["Kingsley", "John", "Ahmed"]
return(
<div>
{ names.map((name, index) => {
return <Counter key={index} name={name} />
})}
</div>
)
}
هنگامی که کلیدها را اختصاص می دهید، React یک شمارنده جداگانه با هر آیتم مرتبط می کند. به این ترتیب، می تواند هر تغییری را که در آرایه ایجاد می کنید منعکس کند.
یکی دیگر از موارد استفاده از کلید پیشرفته
همچنین می توانید از کلیدها برای مرتبط کردن یک عنصر با عنصر دیگر استفاده کنید. برای مثال، ممکن است بخواهید یک عنصر ورودی را با عناصر مختلف بسته به مقدار متغیر حالت مرتبط کنید.
برای نشان دادن، مؤلفه App را تغییر دهید:
import { useState } from "react"
export default function App() {
const [isKingsley, setIsKingsley] = useState(true)
return(
<div>
{ isKingsley ? <div>Kingsley's Score</div> : <div>Sally's score</div> }
<input key={ isKingsley? "Kingsley" : "Sally" } type="number"/>
<br />
<button onClick={() => setIsKingsley(k => !k)}> Swap </button>
</div>
)
}
اکنون، هر بار که بین عناصر
نکات بیشتر برای بهینه سازی برنامه های React
بهینه سازی کد کلید ایجاد یک تجربه کاربری دلپذیر در وب یا اپلیکیشن موبایل شما است. دانستن تکنیک های مختلف بهینه سازی می تواند به شما کمک کند از برنامه های React خود بیشترین بهره را ببرید.
بهترین بخش این است که می توانید بیشتر این تکنیک های بهینه سازی را با برنامه های React Native نیز اعمال کنید.