جدول محتوایی
5 خطا و ارور رایج ری اکت (React.js) و راه حل ان ها
مهم نیست که یک توسعه دهنده React با چندین سال تجربه هستید یا تازه در این زمینه شروع کرده اید، تضمین می شود که در برخی مواقع با پیام خطا/ارور ری اکت (react) مواجه خواهید شد. اینکه کدی بنویسید که باعث این خطاها شود مهم نیست – هیچ کس کد کاملی نمی نویسد، و ما خوش شانس هستیم که React با اطمینان از اینکه در مسیر درست قرار داریم به ما کمک می کند.
با این حال، آنچه مهم است رویکرد شما برای حل این پیام های خطا است. برخورد با آنها، جستجوی آنها در گوگل، و اصلاح کد خود بر اساس تجربیات دیگران یکی از راه ها است.
راه دیگر – و شاید بهتر – درک جزئیات پشت خطا و اینکه چرا در وهله اول یک مشکل است را درک کنید.
این مقاله با مرور برخی از ارور های رایج ری اکت (React) و توضیح معنای آنها، پیامدهای آنها و نحوه رفع آنها به شما در درک این جزئیات کمک میکند.
پیش از ادامه ی مقاله ، در صورت نیاز به خرید سرور مجازی ایران به سایت ایرانیکاسرور مراجعه کرده و از پلن های فوق العاده با قیمت های عالی دیدن کنید.
1. ارور : هر المنت child باید دارای یک کلید (key) منحصر به فرد باشد
import { Card } from "./Card"; const data = [ { id: 1, text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }, { id: 2, text: "Phasellus semper scelerisque leo at tempus." }, { id: 3, text: "Duis aliquet sollicitudin neque," } ]; export default function App() { return ( <div className="container"> {data.map((content) => ( <div className="card"> <Card text={content.text} /> </div> ))} </div> ); }
یکی از رایجترین ارور ها در توسعه React، گرفتن آیتمهای یک آرایه و استفاده از یک کامپوننت برای رندر کردن آنها بر اساس محتوای آیتم است.
به لطف JSX، ما میتوانیم به راحتی آن منطق را با استفاده از تابع Array.map در کامپوننت خود جاسازی کنیم و اجزای مورد نظر را از callback برگردانیم.
با این حال، دریافت ارور React در کنسول مرورگرتان نیز معمول است که میگوید هر المنت child در فهرست باید یک کلید منحصربهفرد داشته باشد. احتمالاً قبل از اینکه عادت کنید به هر child یک کلید منحصر به فرد بدهید، چندین بار با این هشدار مواجه خواهید شد، به خصوص اگر تجربه کمتری در React داشته باشید. اما چگونه آن را قبل از اینکه این عادت را شکل دهید برطرف کنید؟
راه حل
همانطور که اخطار نشان می دهد، شما باید یک پایه key
را به بیرونی ترین عنصر JSX که از بازگشت به تماس نقشه برمی گردانید اضافه کنید.
با این حال، چندین الزام برای کلیدی که می خواهید استفاده کنید وجود دارد. کلید باید ویژگی های زیر را داشته باشد:
- یا یک رشته یا یک عدد
- منحصر به فرد برای آن آیتم خاص در لیست
- نماینده آن مورد در لیست در سراسر رندرها
export default function App() { return ( <div className="container"> {data.map((content) => ( <div key={content.id} className="card"> <Card text={content.text} /> </div> ))} </div> ); }
اگرچه اگر به این الزامات پایبند نباشید، برنامه شما کرش نمی کند، اما می تواند منجر به برخی اتفاقات های غیرمنتظره و اغلب ناخواسته شود.
React از این کلیدها برای تعیین اینکه کدام یک از کودکان در یک لیست تغییر کرده اند استفاده می کند و از این اطلاعات برای تعیین اینکه کدام بخش از DOM قبلی قابل استفاده مجدد است و در هنگام رندر مجدد اجزا باید کدام قسمت ها را دوباره محاسبه کند استفاده می کند. بنابراین، همیشه توصیه می شود این کلیدها را اضافه کنید.
2. جلوگیری از استفاده Index Array در کلیدها
با تکیه بر هشدار قبلی، ما به هشدار ESLint به همان اندازه رایج در مورد همان موضوع می پردازیم.
این اخطار اغلب بعد از اینکه عادت به اضافه کردن یک پایه کلیدی با JSX حاصل از یک لیست کردید، نشان داده میشود.
import { Card } from "./Card"; // Notice that we don't include pre-generated identifiers anymore. const data = [ { text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit." }, { text: "Phasellus semper scelerisque leo at tempus." }, { text: "Duis aliquet sollicitudin neque," } ]; export default function App() { return ( <div className="container"> {data.map((content, index) => ( <div key={index} className="card"> <Card text={content.text} /> </div> ))} </div> ); }
گاهی اوقات، شما یک شناسه منحصر به فرد متصل به داده های خود نخواهید داشت. یک راه حل آسان استفاده از ایندکس مورد فعلی در لیست است.
با این حال، مشکل استفاده از شاخص آیتم در آرایه به عنوان کلید آن این است که نماینده آن آیتم خاص در رندرها نیست.
بیایید بگوییم که ما یک لیست با چندین مورد داریم و کاربر با حذف مورد دوم با آنها تعامل دارد. برای اولین مورد، هیچ چیز در ساختار DOM زیرین آن تغییر نکرده است. این مقدار در کلید آن منعکس می شود که 0 است و ثابت می ماند.
برای مورد سوم و فراتر از آن، محتوای آنها تغییر نکرده است، بنابراین ساختار زیربنایی آنها نیز نباید تغییر کند. با این حال، پایه کلید از همه موارد دیگر تغییر خواهد کرد زیرا کلیدها بر اساس شاخص آرایه (index array) هستند.
React فرض می کند که آنها تغییر کرده اند و ساختار خود را دوباره محاسبه می کنند – که امری کاملا غیر ضروری است. اینکار بر عملکرد تأثیر منفی می گذارد و همچنین می تواند منجر به مشکلات مختلف شود.
راه حل
برای حل این مشکل، مهم است که به یاد داشته باشید که کلیدها لزوماً نباید شناسه باشند. تا زمانی که آنها منحصر به فرد و نماینده ساختار DOM حاصل هستند، هر کلیدی که می خواهید استفاده کنید کار خواهد کرد.
export default function App() { return ( <div className="container"> {data.map((content) => ( <div key={content.text} className="card">{/* This is the best we can do, but it works */} <Card text={content.text} /> </div> ))} </div> ); }
3. آپدیت ری اکت روی مولفه ی mount نشده
هنگامی که با دادههای ناهمگام یا جریانهای منطقی در اجزای خود سروکار دارید، ممکن است با یک خطای زمان اجرا در کنسول مرورگر خود مواجه شوید که به شما میگوید نمیتوانید بهروزرسانی وضعیت را روی مؤلفهای که قبلاً نصب شده است انجام دهید.
مسئله این است که در جایی از درخت اجزای شما، یک بهروزرسانی وضعیت بر روی مؤلفهای که قبلاً نصب نشده است، راهاندازی میشود.
const Component = () => { const [data, setData] = useState(null); useEffect(() => { fetchAsyncData().then((data) => setData(data)); }, []); // ... };
این به دلیل یک به روز رسانی حالت است که به یک درخواست همگام سازی(async) وابسته است. درخواست async از جایی در چرخه حیات یک مؤلفه (مانند داخل یک useEffect Hook) شروع می شود، اما تکمیل آن مدتی طول می کشد.
در همین حال، کامپوننت قبل ان unmount میشود (بهدلیل تعاملات کاربر)، اما درخواست اولیه همگامسازی همچنان تمام میشود – زیرا به چرخه عمر React متصل نیست – و یک بهروزرسانی حالت را برای مؤلفه راهاندازی میکند. خطا در اینجا ایجاد می شود زیرا مؤلفه دیگر وجود ندارد.
راه حل
راه های مختلفی برای پرداختن به این موضوع وجود دارد که همه آنها در دو مفهوم متفاوت خلاصه می شوند. اول، میتوان ردیابی اینکه آیا کامپوننت نصب شده است یا خیر، و ما میتوانیم اقداماتی را بر اساس آن انجام دهیم.
با وجود اینکه ای روش کار می کند، توصیه نمی شود. مشکل این روش این است که به طور غیر ضروری یک مرجع از اجزای نصب نشده را در اطراف نگه میدارد، که باعث نشت حافظه و مشکلات عملکرد میشود.
const Component = () => { const [data, setData] = useState(null); const isMounted = useRef(true); useEffect(() => { fetchAsyncData().then(data => { if(isMounted.current) { setData(data); } }); return () => { isMounted.current = false; }; }, []); // ... }
راه دوم و بهتر – لغو درخواست async زمانی است که کامپوننت جدا می شود.
برخی از کتابخانههای درخواستهای همگامسازی از قبل مکانیزمی برای لغو چنین درخواستی دارند. اگر چنین است، به همان اندازه ساده است که درخواست را در حین پاکسازی پاسخ تماس useEffect Hook لغو کنید.
اگر از چنین کتابخانه ای استفاده نمی کنید، می توانید با استفاده از AbortController به همین کار دست پیدا کنید. تنها معایب این روشهای لغو این است که کاملاً به پیادهسازی کتابخانه یا پشتیبانی مرورگر وابسته هستند.
const Component = () => { const [data, setData] = useState(null); useEffect(() => { const controller = new AbortController(); fetch(url, { signal: controller.signal }).then((data) => setData(data)); return () => { controller.abort(); } }, []); // ... };
4. جلوگیری از رندر شدن بیش از حد
React تعداد رندرها را برای جلوگیری از یک حلقه یا لوپ بی نهایت محدود می کند.
حلقه های بی نهایت بلای جان هر توسعه دهنده ای هستند و توسعه دهندگان React نیز از این قاعده مستثنی نیستند.
خوشبختانه، React کار بسیار خوبی برای شناسایی آنها انجام می دهد و قبل از اینکه کل دستگاه شما کرش کند به شما هشدار می دهد.
راه حل
همانطور که اخطار نشان می دهد، مشکل این است که مؤلفه شما دوباره رندرهای بیش از حد مجاز را راه اندازی می کند.
این زمانی اتفاق می افتد که کامپوننت شما در مدت زمان بسیار کوتاهی تعداد زیادی به روز رسانی حالت را در صف قرار می دهد.
متداول ترین دلایل برای ایجاد حلقه های بی نهایت عبارتند از:
- انجام به روز رسانی حالت به طور مستقیم در رندر
- عدم ارائه پاسخ تماس مناسب به کنترل کننده رویداد
اگر با این هشدار خاص مواجه شدید، مطمئن شوید که این دو جنبه از کامپوننت خود را بررسی کنید:
const Component = () => { const [count, setCount] = useState(0); setCount(count + 1); // State update in the render return ( <div className="App"> {/* onClick doesn't receive a proper callback */} <button onClick={setCount((prevCount) => prevCount + 1)}> Increment that counter </button> </div> ); }
قرار دادن عناصر JSX مجاور در یک تگ محصور
یکی از بزرگترین مزایای React این است که می تواند یک برنامه کامل را با ترکیب بسیاری از اجزای کوچکتر بسازد.
هر کامپوننت می تواند بخش UI خود را به شکل JSX که باید رندر شود ، تعریف کند که در نهایت به کل ساختار DOM برنامه کمک می کند:
const Component = () => ( <div><NiceComponent /></div> <div><GoodComponent /></div> );
با توجه به ماهیت ترکیبی React، یک کار معمول که باید امتحان کرد، برگرداندن دو عنصر JSX در ریشه یک جزء است که فقط در داخل کامپوننت دیگری استفاده میشود.
با این حال، انجام این کار به طور شگفت انگیزی به توسعه دهندگان React هشدار می دهد که به آنها می گوید باید عناصر JSX مجاور را در برچسب های محصور قرار دهند.
از دیدگاه توسعه دهندگان متوسط React، این کامپوننت فقط در داخل کامپوننت دیگری استفاده می شود. بنابراین، در مدل ذهنی آنها، بازگرداندن دو عنصر از یک مؤلفه کاملاً منطقی است زیرا ساختار DOM حاصل یکسان است، فرقی نمیکند یک عنصر بیرونی در این مؤلفه تعریف شده باشد یا مؤلفه والد.
با این حال، React قادر به انجام این فرض نیست. به طور بالقوه، این مؤلفه می تواند در ریشه استفاده شود و برنامه را خراب کند، زیرا منجر به ساختار DOM نامعتبر می شود.
راه حل
توسعه دهندگان React همیشه باید چندین عنصر JSX را که از یک کامپوننت بازگردانده شده اند در یک تگ محصور قرار دهند. اگر مطمئن هستید که کامپوننت به عنصر بیرونی نیاز ندارد، این می تواند یک عنصر، یک جزء یا بخشی از react باشد.
const Component = () => ( <React.Fragment> <div><NiceComponent /></div> <div><GoodComponent /></div> </React.Fragment> );
جمع بندی
بدون توجه به میزان تجربه شما، مواجه شدن با ارور رایج ری اکت در طول کد نویسی، بخش اجتناب ناپذیری از فرآیند ان است.
با این حال، نحوه مدیریت این ارور ها نیز نشان دهنده توانایی شما به عنوان یک توسعه دهنده React است. برای انجام این کار به درستی، لازم است این خطاها را درک کنید و بدانید چرا رخ می دهند.
برای کمک به شما در این زمینه، این مقاله 5 مورد از رایجترین پیامهای خطای React را که در طول توسعه React با آنها مواجه خواهید شد، مرور کرد. ما معنای پشت پیامهای خطا، خطای اساسی، راه حل ان ها، و اگر خطاها را برطرف نکنید چه اتفاقی میافتد را پوشش دادیم. موفق باشید!