25 نکته برتر React که هر برنامهنویسی باید بداند – قسمت 2

Summarize this content to 400 words in Persian Lang
این قسمت دوم از سری نکات React است. اگر قسمت اول را بررسی نکرده اید، می توانید آن را در اینجا بررسی کنید.
پس بیایید شروع کنیم.
1. از برنامه افزودنی مرورگر LocatorJS برای پیمایش سریع بین کد منبع استفاده کنید
از افزونه مرورگر LocatorJS برای پیمایش سریع به کد منبع در IDE مورد علاقه خود (VS Code) فقط با کلیک بر روی هر یک از عناصر UI نمایش داده شده در مرورگر استفاده کنید.
این پسوند زمانی واقعاً مفید است که یک برنامه بزرگ دارید و می خواهید بفهمید کدام فایل حاوی کد رابط کاربری نمایش داده شده است.
همچنین زمانی مفید است که کد توسط شخص دیگری نوشته شده باشد و شما بخواهید کد را اشکال زدایی کنید.
استفاده کنید Option/Alt + کلیک کنید برای رفتن به کد منبع
وقتی با کد کتابخانه Material UI نوشته شده توسط دیگران کار میکنید و میخواهید کد دقیق هر بخشی از UI را پیدا کنید، این برنامه افزودنی نجاتبخش است.
2. هرگز URL API را در برنامه هاردکد قرار ندهید
هر زمان که یک تماس API برقرار می کنید، هرگز URL API را کد سخت نکنید، در عوض، ایجاد کنید src/utils/constants.js یا یک فایل مشابه و اضافه کنید API URL داخل آن به این صورت:
export const BASE_API_URL = “https://jsonplaceholder.typicode.com”;
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
و هر جا که میخواهید یک تماس API برقرار کنید، فقط از آن ثابت با استفاده از نحو تحت اللفظی الگو مانند زیر استفاده کنید:
// posts.jsx
import { BASE_API_URL } from ‘../utils/constants.js’;
const {data} = await axios.get(`${BASE_API_URL}/posts`);
// users.jsx
import { BASE_API_URL } from ‘../utils/constants.js’;
const {data} = await axios.get(`${BASE_API_URL}/users`);
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
و با این تغییر، اگر بعداً خواستید آن را تغییر دهید BASE_API_URL مقدار، پس نیازی به تغییر آن در چندین فایل ندارید.
فقط باید آن را در قسمت آپدیت کنید constants.js فایل، در همه جا منعکس خواهد شد.
PS: شما حتی می توانید ذخیره کنید BASE_API_URL ارزش در .env فایل به جای ذخیره آن در constants.js فایل تا بتوانید به راحتی آن را بسته به محیط توسعه یا تولید تغییر دهید.
3. از صادرات بشکه برای سازماندهی اجزای واکنش استفاده کنید
وقتی روی یک پروژه بزرگ React کار می کنید، ممکن است چندین پوشه حاوی اجزای مختلف داشته باشید.
در چنین مواردی، اگر از اجزای مختلف در یک فایل خاص استفاده میکنید، فایل شما حاوی عبارات وارداتی زیادی مانند زیر است:
import ConfirmModal from ‘./components/ConfirmModal/ConfirmModal’;
import DatePicker from ‘./components/DatePicker/DatePicker’;
import Tooltip from ‘./components/Tooltip/Tooltip’;
import Button from ‘./components/Button/Button’;
import Avatar from ‘./components/Avatar/Avatar’;
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
که ظاهر خوبی ندارد زیرا با افزایش تعداد اجزاء، تعداد اظهارنامه های واردات نیز افزایش می یابد.
برای رفع این مشکل، می توانید یک index.js فایل در پوشه والد (components) پوشه کنید و تمام کامپوننت ها را به صورت صادراتی با نام از آن فایل مانند زیر صادر کنید:
export { default as ConfirmModal } from ‘./ConfirmModal/ConfirmModal’;
export { default as DatePicker } from ‘./DatePicker/DatePicker’;
export { default as Tooltip } from ‘./Tooltip/Tooltip’;
export { default as Button } from ‘./Button/Button’;
export { default as Avatar } from ‘./Avatar/Avatar’;
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
این کار فقط یک بار باید انجام شود. اکنون، اگر در هر یک از فایل ها می خواهید به هر مؤلفه ای دسترسی داشته باشید، می توانید به راحتی آن را با استفاده از import نامگذاری شده در یک خط مانند زیر وارد کنید:
import {ConfirmModal, DatePicker, Tooltip, Button, Avatar} from ‘./components’;
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
که همان است
import {ConfirmModal, DatePicker, Tooltip, Button, Avatar} from ‘./components/index’;
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
این یک روش استاندارد هنگام کار بر روی پروژه های صنعتی/شرکتی بزرگ است.
این الگو به عنوان الگوی بشکه ای شناخته می شود که یک الگوی سازماندهی فایل است که به ما امکان می دهد همه ماژول ها را در یک فهرست از طریق یک فایل واحد صادر کنیم.
در اینجا یک نسخه ی نمایشی CodeSandbox وجود دارد تا آن را در عمل ببینید.
4. ذخیره کلید API در فایل .env در React Application آن را خصوصی نکنید
اگر از a استفاده می کنید .env فایل برای ذخیره اطلاعات خصوصی مانند API_KEY در برنامه React شما، در واقع آن را خصوصی نمی کند.
برنامه React شما در سمت کلاینت/مرورگر اجرا میشود، بنابراین هر کسی همچنان میتواند آن را ببیند API_KEY به عنوان بخشی از استفاده می شود API URL از تب شبکه
راه بهتر برای خصوصی کردن آن، ذخیره آن در قسمت پشتیبان است.
توجه داشته باشید که، حتی با استفاده از .env فایل درون React حفظ حریم خصوصی مطلق را تضمین نمی کند، توصیه می شود این روش را برای یک لایه امنیتی بیشتر دنبال کنید.
بنابراین هیچ کس نمی تواند آن را پیدا کند API_KEY مستقیماً در کد منبع برنامه شما.
همچنین، مطمئن شوید که فشار ندهید .env به دلایل امنیتی در GitHub قرار دهید. می توانید با اضافه کردن آن به آن به آن دست پیدا کنید .gitignore فایل
5. ارسال یک کلید متفاوت به کامپوننت باعث ایجاد مجدد کامپوننت می شود
<BookForm
key={book.id}
book={book}
handleSubmit={handleSubmit}
/>
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
هر زمان که کلید دیگری را به کامپوننت می دهیم، کامپوننت دوباره ایجاد می شود و تمام داده ها و وضعیت آن بازنشانی می شود.
این گاهی اوقات مفید است اگر نمی خواهید اطلاعات قبلی را حفظ کنید / وضعیت مؤلفه را پس از مدتی بازنشانی کنید.
به عنوان مثال، در یک صفحه واحد، مدال های مختلفی را برای نمایش اطلاعات مختلف باز می کنید، سپس می توانید یک کلید منحصر به فرد را برای هر مدال ارسال کنید، بنابراین هر بار که مدال را باز می کنید، اطلاعات قبلی حفظ نمی شود و می توانید برای نمایش داده های مودال صحیح مربوطه.
بنابراین این یکی از دلایلی است که شما به یک کلید منحصر به فرد نیاز دارید که در حین استفاده از روش نقشه آرایه در حین رندر مجدد تغییر نکند.
زیرا هر زمان که کلید تغییر کند، React آن عنصر و تمام عناصر فرزند آن از جمله مؤلفههایی را که درون آن عنصر والد قرار دادهاید، دوباره ایجاد میکند و باعث مشکلات عملکردی عمده میشود.
6. با ایجاد پوشه های جداگانه برای هر یک، اجزا را سازماندهی کنید
هر زمان که کامپوننتی را ایجاد میکنید، آن مؤلفه را مستقیماً در پوشه مؤلفهها قرار ندهید.
در عوض، پوشههای مجزا برای اجزای جداگانه در داخل پوشه کامپوننتها مانند این ایجاد کنید:
— components
— header
— Header.jsx
— Header.css
— Header.test.js
— footer
— Footer.jsx
— Footer.css
— Footer.test.js
— sidebar
— Sidebar.jsx
— Sidebar.css
— Sidebar.test.js
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
همانطور که در بالا می بینید، ما یک را ایجاد کرده ایم header،footer، و sidebar پوشه های داخل components پوشه، و در داخل header پوشه، تمام فایل های مربوط به header نگهداری می شوند.
در مورد هم همینطور است footer و sidebar پوشه ها
7. از Redux برای هر برنامه React استفاده نکنید
هنگام ساختن یک برنامه React در ابتدا از خود Redux استفاده نکنید.
برای برنامه های کوچکتر استفاده از React Context API یا useReducer hook برای مدیریت برنامه React کافی است.
در زیر برخی از موارد استفاده وجود دارد که می توانید Redux را انتخاب کنید.
برای مدیریت وضعیت جهانی: هنگامی که یک وضعیت برنامه جهانی مانند احراز هویت، اطلاعات نمایه یا داده ای دارید که باید بین چندین مؤلفه به اشتراک گذاشته شود.
برای به اشتراک گذاشتن داده ها بین اجزای غیر مرتبط: زمانی که برنامه شما دارای چندین صفحه با استفاده از مسیریابی است، و بنابراین نمیتوانید حالت مولفه والد را بالا ببرید
به روز رسانی های ایالتی ثابت: Redux یک منبع از حقیقت را برای وضعیت برنامه شما اعمال می کند و به روز رسانی و حفظ وضعیت برنامه شما را به شیوه ای ثابت آسان تر می کند.
مقیاس پذیری: Redux میتواند با ارائه یک الگوی واضح برای مدیریت وضعیت با افزایش اندازه و پیچیدگی برنامه شما، به مقیاس برنامه شما کمک کند.
برای یادگیری Redux + Redux Toolkit از ابتدا می توانید این دوره را دنبال کنید.
8. از روش console.count برای پیدا کردن تعداد رندرهای مجدد کامپوننت استفاده کنید
گاهی اوقات می خواهیم بدانیم که یک خط کد خاص چند بار اجرا می شود.
شاید بخواهیم بدانیم یک تابع خاص چند بار اجرا می شود.
در این صورت می توانیم از a استفاده کنیم console.count روش با ارسال یک رشته منحصر به فرد به عنوان آرگومان.
به عنوان مثال، اگر یک کد React دارید و می خواهید بفهمید که چند بار کامپوننت دوباره رندر می شود، به جای اضافه کردن console.log و با شمارش دستی تعداد دفعاتی که در کنسول چاپ شده است، فقط می توانید اضافه کنید console.count(‘render’) در جزء
و پیام رندر را به همراه تعداد دفعات اجرا مشاهده خواهید کرد.
9. از اعلام وضعیت جدید برای ذخیره همه چیز در داخل یک کامپوننت خودداری کنید
قبل از اعلام وضعیت جدید در یک جزء، همیشه دو بار فکر کنید اگر واقعاً نیاز دارید که آن اطلاعات را در حالت ذخیره کنید.
زیرا هنگامی که یک متغیر حالت را اعلام کردید، باید فراخوانی کنید setState برای بهروزرسانی مقدار حالت، و هر زمان که وضعیت تغییر کند، React مؤلفهای که آن حالت را دارد و همچنین تمام مؤلفههای مستقیم و غیرمستقیم فرزند آن را دوباره ارائه میکند.
بنابراین با معرفی یک حالت واحد، یک رندر مجدد اضافی در برنامه خود اضافه می کنید، و اگر برخی از مؤلفه های فرزند سنگین دارید که فیلتر، مرتب سازی یا دستکاری داده های زیادی را انجام می دهند، به روز رسانی رابط کاربری با تغییرات جدید زمان بیشتری می برد. .
اگر فقط نیاز دارید مقداری را ردیابی کنید که به هیچ جزء فرزندی منتقل نمیکنید یا در حین رندر استفاده نمیکنید، از هوک useRef برای ذخیره آن اطلاعات استفاده کنید.
زیرا به روز رسانی مقدار ref باعث رندر مجدد کامپوننت نمی شود.
10. هر عملکردی را در داخل یک جزء اعلام نکنید
هنگامی که یک تابع را در داخل یک کامپوننت اعلام می کنید، اگر آن تابع به وضعیت یا اجزای کامپوننت بستگی ندارد، آن را خارج از کامپوننت اعلام کنید.
زیرا در هر رندر مجدد کامپوننت، همه توابع در کامپوننت عملکردی دوباره ایجاد میشوند، بنابراین اگر توابع زیادی در یک جزء دارید، ممکن است برنامه را کند کند.
به کد زیر دقت کنید:
const getShortDescription = (description) => {
return description.slice(0, 20);
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
تابع فوق هیچ گونه وابستگی به حالت یا مقدار prop ندارد.
ما فقط یک مقدار را برای دریافت متن کوتاه شده ارسال می کنیم. بنابراین نیازی به اعلام آن در داخل کامپوننت نیست.
همچنین، اگر به عملکرد توصیف کوتاه یکسان در اجزای مختلف نیاز دارید، به جای تکرار کد در آن اجزا، تابع را به فایل دیگری مانند utils/functions.js و آن را از آنجا صادر کنید و در اجزای مورد نیاز استفاده کنید.
این باعث می شود اجزای شما به راحتی قابل درک باشند.
11. برنامه های React خود را حداقل به نسخه 18 ارتقا دهید
با React نسخه 18، عملکرد برنامه بهتری در مقایسه با نسخه کمتر از 18 دارید.
با نسخه 18، React بهروزرسانیهای چند حالت را در یک چرخه رندر واحد جمع میکند. بنابراین اگر چندین تماس حالت تنظیم شده در تابعی مانند زیر دارید:
const handleUpdate = (user) => {
setCount(count => count + 1);
setIsOpen(open => !open);
setUser(user);
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
سپس فقط به دلیل وجود سه تماس به روز رسانی حالت، React کامپوننت را سه بار دوباره رندر نمی کند، در عوض، تنها یک بار رندر می شود.
در نسخه React کمتر از 18، فقط بهروزرسانیهای حالت در داخل توابع مدیریت رویداد با هم جمع میشوند، اما بهروزرسانیها در داخل قرار میگیرند. promises، setTimeout تابع، کنترلکنندههای رویداد بومی یا هر کنترلکننده رویداد دیگری دستهبندی نمیشوند.
اگر از نسخه React کمتر از 18 استفاده می کنید، برای کد بالا، چون سه حالت به روز رسانی وجود دارد، کامپوننت سه بار رندر می شود که عملکرد ناکارآمدی دارد.
با نسخه 18، به روز رسانی ها را در داخل قرار دهید timeouts، promises، کنترل کننده های رویداد بومی یا هر رویداد دیگری با هم جمع می شوند، بنابراین برای کد بالا، ارائه کد فقط یک بار اتفاق می افتد.
12. از محل صحیح برای راه اندازی QueryClient در Tanstack Query/React Query استفاده کنید
هنگام استفاده از Tanstack Query / React Query، هرگز ایجاد نکنید QueryClient نمونه داخل کامپوننت
را QueryClient Query Cache را نگه می دارد، بنابراین اگر یک کلاینت جدید در داخل یک جزء ایجاد می کنید، با استفاده از کد زیر:
const queryClient = new QueryClient();
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
سپس در هر رندر مجدد مؤلفه، یک کپی جدید از کش کوئری دریافت خواهید کرد. بنابراین داده های پرس و جو شما در حافظه پنهان ذخیره نمی شوند و عملکرد ذخیره سازی آن طور که انتظار می رود کار نخواهد کرد.
پس همیشه خلق کنید QueryClient نمونه خارج از کامپوننت به جای داخل کامپوننت.
// Instead of writing code like this:
const App = () => {
// ❌ Dont’ create queryClient inside component. This is wrong.
const queryClient = new QueryClient();
return (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
}
// write it like this:
// ✅ This is correct place to create queryClient
const queryClient = new QueryClient();
const App = () => {
return (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
اگر می خواهید React Query / Tanstack Query را از ابتدا یاد بگیرید، این دوره را بررسی کنید.
13. از پسوند ReacTree VSCode برای یافتن روابط فرزند والدین استفاده کنید
از پسوند ReacTree VS Code برای مشاهده سریع نمای درختی اجزای برنامه React خود استفاده کنید.
این یک راه عالی برای پیدا کردن روابط اجزای والدین و فرزند است.
14. همیشه هنگام کار با فرم ها از کتابخانه هایی مانند react-hook-form استفاده کنید
هر زمان که با فرمهای ساده و همچنین پیچیده در React کار میکنم، من همیشه کتابخانه react-hook-form را ترجیح میدهم که محبوبترین کتابخانه مرتبط با فرم React است.
از ref به جای حالت برای مدیریت داده های ورودی استفاده می کند که به جلوگیری از مشکلات عملکرد در برنامه کمک می کند.
با استفاده از این کتابخانه، کامپوننت شما روی هر کاراکتر تایپ شده مجدداً رندر نمیشود، در صورتی که خودتان آن را با حالت مدیریت کنید.
شما همچنین از مزیت افزوده روشی آسان برای اجرای اعتبارسنجی واکنشی برای فرم های خود بهره مند می شوید.
همچنین کد کامپوننت شما را بسیار ساده تر و قابل فهم تر می کند.
این یک کتابخانه بسیار قدرتمند است، بنابراین حتی کتابخانه shadcn/ui از آن برای مؤلفه Form خود استفاده می کند.
اگر می خواهید react-hook-form را از ابتدا یاد بگیرید، این مقاله را بررسی کنید.
15. از انتقال تابع setState به عنوان پشتوانه برای اجزای کودک خودداری کنید
هرگز تابع setState را مستقیماً به عنوان یک پایه به هیچ یک از مؤلفه های فرزند مانند زیر منتقل نکنید:
const Parent = () => {
const [state, setState] = useState({
name: ”,
age: ”
})
.
.
.
return (
<Child setState={setState} />
)
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
وضعیت یک جزء باید فقط توسط خود آن جزء تغییر کند.
در اینجا چرا:
این تضمین می کند که کد شما قابل پیش بینی است. اگر setState را مستقیماً به چندین مؤلفه منتقل کنید، تشخیص اینکه وضعیت از کجا تغییر می کند دشوار خواهد بود.
این عدم قابلیت پیش بینی می تواند منجر به رفتار غیرمنتظره شود و اشکال زدایی کد را دشوار کند.
با گذشت زمان، همانطور که برنامه شما رشد می کند، ممکن است لازم باشد نحوه مدیریت حالت را در مؤلفه والد تغییر دهید یا تغییر دهید.
اگر مؤلفههای فرزند به دسترسی مستقیم به setState متکی باشند، این تغییرات میتوانند در پایگاه کد موج بزنند و به بهروزرسانیها در مکانهای مختلف نیاز داشته باشند و خطر ایجاد اشکالات را افزایش دهند.
اگر دادههای حساس بخشی از حالت باشند، انتقال مستقیم setState میتواند به طور بالقوه آن دادهها را در معرض مؤلفههای فرزند قرار دهد و خطرات امنیتی را افزایش دهد.
الگوریتم تطبیق مولفههای React زمانی کارآمدتر عمل میکند که بهروزرسانیهای حالت و props به وضوح در داخل مؤلفهها تعریف شده باشند.
به جای عبور setState به طور مستقیم می توانید کارهای زیر را انجام دهید:
داده ها را به عنوان ابزار ارسال کنید: دادههایی را که مؤلفه فرزند به آن نیاز دارد، بهعنوان پروپوزال ارسال کنید، نه خود تابع setState. به این ترتیب، یک رابط واضح برای مؤلفه فرزند فراهم میکنید تا دادهها را بدون افشای جزئیات پیادهسازی وضعیت دریافت کند.
عملکرد پاس به عنوان پایه: اگر مؤلفه فرزند نیاز به تعامل با وضعیت مؤلفه والد داشته باشد، میتوانید تابعی را به عنوان یک پایه ارسال کنید. یک تابع را در کامپوننت والد اعلام کنید و وضعیت را در آن تابع به روز کنید، می توانید این تابع را به عنوان یک پایه به کامپوننت فرزند منتقل کنید و در صورت نیاز آن را از کامپوننت فرزند فراخوانی کنید.
16. از استفاده از اپراتورهای سه تایی تو در تو خودداری کنید
هنگام استفاده از عملگر سه تایی هرگز از یک شرط فراتر نروید و از نوشتن شرایط تودرتو خودداری کنید.
// Good Practice
{isAdmin ? <Dashboard /> : <Profile /> }
// Bad Practice
{isAdmin ? <Dashboard /> : isSuperAdmin ? <Settings /> : <Profile />}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
استفاده از شرایط تو در تو در هنگام استفاده از اپراتور سه تایی خواندن و نگهداری کد را دشوار می کند، حتی اگر از فرمت کننده ای برای قالب بندی کد استفاده می کنید.
اگر بیش از یک شرط برای بررسی دارید، می توانید از if/else یا switch case یا lookup map استفاده کنید اما هرگز از عملگر سه تایی مانند زیر استفاده نکنید:
if (isAdmin) {
return <Dashboard />;
} else if (isSuperAdmin) {
return <Settings />;
} else {
return <Profile />;
}
// OR
switch (true) {
case isAdmin:
return <Dashboard />;
case isSuperAdmin:
return <Settings />;
default:
return <Profile />;
}
// OR
{isAdmin && <Dashboard />}
{isSuperAdmin && <Settings />}
{!isAdmin && !isSuperAdmin && <Profile />}
// OR use a lookup map like this:
const data = {
isAdmin: <Dashboard />,
isSuperAdmin: Settings />,
Neither: <Profile />
}
// and access the data using data[‘isAdmin’],
// resulting in the Dashboard page being displayed.
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
این نه تنها برای React بلکه در مورد جاوا اسکریپت و سایر زبان های برنامه نویسی نیز صدق می کند.
17. برای هر جزء فایل جداگانه ایجاد نکنید
لازم نیست هر جزء را در یک فایل جداگانه ایجاد کنید.
اگر مؤلفهای دارید که فقط در یک فایل خاص استفاده میشود و آن مؤلفه فقط حداقل کد JSX را برمیگرداند، میتوانید آن مؤلفه را در همان فایل ایجاد کنید.
این کار از ایجاد غیرضروری فایلهای اضافی جلوگیری میکند و همچنین به درک بهتر کد زمانی که در یک فایل است کمک میکند.
const ProfileDetailsHeader = () => {
return (
<header>
<h1 className=’text-3xl font-bold leading-10′>
Profile Details
</h1>
<p className=’mt-2 text-base leading-6 text-neutral-500′>
Add your details to create a personal touch to your profile.
</p>
</header>
);
};
const Profile = () => {
return (
<ProfileDetailsHeader />
…
<ProfileDetailsFooter />
);
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
18. هرگز اطلاعات خصوصی را مستقیماً در کد ذخیره نکنید
من افراد زیادی را دیده ام که مستقیماً اطلاعات خصوصی خود را مانند پیکربندی Firebase در کدی مانند این می نویسند:
const config = {
apiKey: ‘AIdfSyCrjkjsdscbbW-pfOwebgYCyGvu_2kyFkNu_-jyg’,
projectId: ‘seventh-capsule-78932’,
…
};
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
هرگز این کار را انجام نده این یک مسئله امنیتی مهم است. وقتی فایلی با این پیکربندی را به GitHub فشار میدهید، وقتی شخصی مخزن شما را شبیهسازی میکند، میتواند مستقیماً به دادههای Firebase شما دسترسی داشته باشد.
آنها می توانند داده ها را از Firebase شما اضافه، ویرایش یا حذف کنند.
برای جلوگیری از این مشکل، می توانید یک فایل با نام ایجاد کنید .env در پروژه خود و برای هر ویژگی شی config، یک متغیر محیطی مانند زیر ایجاد کنید:
// If using Vite.js
VITE_APP_API_KEY=AIdfSyCrjkjsdscbbW-pfOwebgYCyGvu_2kyFkNu_-jyg
// access it as import.meta.env.VITE_APP_API_KEY
// If using create-react-app
REACT_APP_API_KEY=AIdfSyCrjkjsdscbbW-pfOwebgYCyGvu_2kyFkNu_-jyg
// and access it as process.env.REACT_APP_API_KEY
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
همچنین، اضافه کنید .env ورود فایل به .gitignore فایل بنابراین به GitHub منتقل نمی شود.
19. همیشه منطق تجاری مؤلفه خود را به قلاب های سفارشی منتقل کنید
در صورت امکان، همیشه سعی کنید از قلاب های سفارشی حداکثر استفاده را ببرید.
همیشه همه منطق تجاری مؤلفه خود و فراخوانی های API را در یک هوک سفارشی قرار دهید.
به این ترتیب کد کامپوننت شما تمیز و قابل درک، نگهداری و آزمایش به نظر می رسد.
const ResetPassword = () => {
const { isPending, sendResetEmail, error } = useResetPassword();
// some JSX
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
20. هر استفاده از هوک سفارشی یک نمونه جدید ایجاد می کند
اکثر توسعه دهندگان React مبتدی این اشتباه را هنگام درک قلاب های سفارشی مرتکب می شوند.
هنگام استفاده از یک قلاب سفارشی خاص در چندین مؤلفه، ممکن است فکر کنید که هر مؤلفه به دادههای مشابهی که از آن قلاب بازگردانده شده است به شرح زیر اشاره میکند:
const [show, toggle] = useToggle();
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
با این حال، این مورد نیست.
هر جزء با استفاده از آن قلاب یک نمونه جداگانه از قلاب خواهد داشت.
در نتیجه، همه حالتها، کنترلکنندههای رویداد و سایر دادههای اعلامشده در آن هوک سفارشی برای هر جزء که از آن قلاب استفاده میکند متفاوت خواهد بود.
بنابراین اگر نیاز به استفاده از دادهها و کنترلکنندههای رویداد یکسان برای همه مؤلفهها دارید، باید قلاب سفارشی را تنها در یک مکان در مؤلفه اصلی همه این مؤلفهها وارد کنید.
سپس، میتوانید دادههای بازگردانده شده توسط هوک سفارشی را به عنوان یک پایه ارسال کنید یا از Context API برای دسترسی به آن از اجزای خاص استفاده کنید.
بنابراین هرگز با استفاده از یک هوک سفارشی در اجزای مختلف اشتباه نکنید، با این فرض که تغییر دادههای هوک از یک مؤلفه بهطور خودکار در مؤلفه دیگر نیز بهروزرسانی میشود.
در اینجا یک نسخه ی نمایشی CodeSandbox وجود دارد تا آن را در عمل ببینید.
21. از از دست دادن ویژگی های حالت هنگام به روز رسانی اشیا با React Hook جلوگیری کنید
هنگام استفاده از اجزای کلاس، اگر حالتی با چندین ویژگی مانند این دارید:
state = {
name: ”,
isEmployed: false
};
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
سپس برای به روز رسانی حالت می توانیم فقط ویژگی را که می خواهیم به روز رسانی کنیم به این صورت مشخص کنیم:
this.setState({
name: ‘David’
});
// OR
this.setState({
isEmployed: true
});
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
بنابراین سایر ویژگی های حالت هنگام به روز رسانی هیچ ویژگی از بین نخواهند رفت.
اما هنگام کار با قلاب های React، اگر حالت یک شی مانند زیر ذخیره می کند:
const [state, setState] = useState({
name: ”,
isEmployed: false
});
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
سپس هنگام بهروزرسانی یک ویژگی حالت خاص، بهصورت دستی باید ویژگیهای قبلی را مانند این پخش کنید:
setState((prevState) => {
return {
…prevState,
name: ‘David’
};
});
// OR
setState((prevState) => {
return {
…prevState,
isEmployed: true
};
});
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
اگر مقادیر حالت قبلی را پخش نکنید، سایر ویژگی ها از بین خواهند رفت.
زیرا هنگام استفاده از حالت به طور خودکار ادغام نمی شود useState قلاب با شی
22. افزودن دینامیک کلاس های Tailwind در React کار نمی کند
اگر از Tailwind CSS برای استایلسازی استفاده میکنید و میخواهید به صورت پویا هر کلاسی را اضافه کنید، کد زیر کار نخواهد کرد.
<div className={`bg-${isActive ? ‘red-200’ : ‘orange-200’}`}>
Some content
</div>
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
این به این دلیل است که در فایل CSS نهایی شما، Tailwind CSS فقط شامل کلاسهایی است که در طول اسکن اولیه فایل شما وجود دارد.
بنابراین کد بالا به صورت پویا اضافه می کند bg-red-200 یا bg-orange-200 کلاس به div اما CSS آن اضافه نخواهد شد بنابراین CSS اعمال شده روی آن div را نخواهید دید.
بنابراین برای رفع این مشکل، ابتدا باید کل کلاس را به صورت زیر تعریف کنید:
<div className={`${isActive ? ‘bg-red-200’ : ‘bg-orange-200’}`}>
Some content
</div>
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
اگر کلاسهای زیادی دارید که باید به صورت شرطی اضافه شوند، میتوانید یک شی را با نامهای کلاس کامل مانند این تعریف کنید:
const colors = {
purple: ‘bg-purple-300’,
red: ‘bg-red-300’,
orange: ‘bg-orange-300’,
violet: ‘bg-violet-300’
};
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
و به این صورت از آن استفاده کنید:
<div className={colors[‘red’]}>
Some content
</div>
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
23. هنگام استفاده از روتر React، همیشه مسیر صفحه پیش فرض یا یافت نشد را اضافه کنید
هر زمان که با استفاده از روتر React مسیریابی را در React پیاده سازی می کنید، فراموش نکنید که یک مسیر برای یک مسیر نامعتبر (صفحه یافت نشد) اضافه کنید.
زیرا اگر شخصی به مسیری که وجود ندارد پیمایش کند، یک صفحه خالی می بیند.
برای راه اندازی یک مسیر نامعتبر، می توانید جزء مسیر نامعتبر را به عنوان آخرین مسیر در لیست مسیرها مانند شکل زیر ذکر کنید.
<Routes>
<Route path=”/” element={<Home />} />
.
.
.
<Route path=”*” element={<NotFoundPage />} />
</Routes>
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
اگر نمیخواهید مؤلفه NotFoundPage را برای یک مسیر نامعتبر نمایش دهید، میتوانید تغییر مسیر را طوری تنظیم کنید که به صورت خودکار به صفحه اصلی مسیر نامعتبر مانند شکل زیر هدایت شود.
<Routes>
<Route path=”/” element={<Home />} />
.
.
.
<Route path=”*” element={<Navigate to=”/” />} />
</Routes>
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
24. از Spread Operator برای انتقال آسان ویژگی های شی به کامپوننت فرزند استفاده کنید
اگر وسایل زیادی دارید که باید به یک کامپوننت ارسال شوند، بهجای اینکه موارد منفرد را مانند این ارسال کنید:
const Users = ({users}) => {
return (
<div>
{users.map(({ id, name, age, salary, isMarried }) => {
return (
<User
key={id}
name={name}
age={age}
salary={salary}
isMarried={isMarried}
/>
)
})}
</div>
)
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
شما می توانید از عملگر spread برای عبور آسان پروپ های مانند زیر استفاده کنید:
const Users = ({users}) => {
return (
<div>
{users.map((user) => {
return (
<User key={user.id} {…user} />
)
})}
</div>
)
}
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
با این حال، از این نحو گسترش بیش از حد استفاده نکنید. اگر شیئی که در حال پخش آن هستید دارای خواص زیادی است، ارسال آنها به صورت دستی همانطور که در کد اول نشان داده شده است بهتر از پخش کردن است.
25. انتقال حالت به هوک سفارشی، مولفه را از رندر مجدد باز نمی دارد
هر زمان که از هر قلاب سفارشی در هر یک از مؤلفه ها استفاده می کنید و اگر وضعیت داخل آن قلاب سفارشی تغییر کند، مؤلفه ای که از آن قلاب سفارشی استفاده می کند دوباره رندر می شود.
به کد زیر دقت کنید:
export const useFetch = () => {
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
// some code to fetch and update data
return { data, isLoading };
};
const App = () => {
const { data, isLoading } = useFetch();
// return some JSX
};
وارد حالت تمام صفحه شوید
از حالت تمام صفحه خارج شوید
همانطور که در کد بالا مشاهده می شود، useFetch یک قلاب سفارشی است بنابراین هر زمان که data یا isLoading تغییر حالت، App کامپوننت دوباره رندر می شود.
بنابراین اگر App مؤلفه در حال رندر کردن برخی مؤلفه های فرزند دیگر است، آن فرزند مستقیم و همچنین مؤلفه های فرزند غیرمستقیم نیز هنگامی که data یا isLoading ایالت از useFetch تغییرات قلاب سفارشی
بنابراین فقط به این دلیل که شما آن را بازسازی کرده اید App حالت حرکت جزء در داخل قلاب سفارشی به این معنی نیست که App کامپوننت دوباره رندر نمی شود.
با تشکر برای خواندن!
آیا می خواهید با محتوای معمولی مربوط به جاوا اسکریپت، React و Node.js به روز بمانید؟ من را در لینکدین دنبال کنید.
اشتراک مادام العمر / حرفه ای را دریافت کنید
Master JavaScript، React و Node.js
در کانال یوتیوب من مشترک شوید
GitHub من
این قسمت دوم از سری نکات React است. اگر قسمت اول را بررسی نکرده اید، می توانید آن را در اینجا بررسی کنید.
پس بیایید شروع کنیم.
1. از برنامه افزودنی مرورگر LocatorJS برای پیمایش سریع بین کد منبع استفاده کنید
از افزونه مرورگر LocatorJS برای پیمایش سریع به کد منبع در IDE مورد علاقه خود (VS Code) فقط با کلیک بر روی هر یک از عناصر UI نمایش داده شده در مرورگر استفاده کنید.
این پسوند زمانی واقعاً مفید است که یک برنامه بزرگ دارید و می خواهید بفهمید کدام فایل حاوی کد رابط کاربری نمایش داده شده است.
همچنین زمانی مفید است که کد توسط شخص دیگری نوشته شده باشد و شما بخواهید کد را اشکال زدایی کنید.
استفاده کنید Option/Alt + کلیک کنید برای رفتن به کد منبع
وقتی با کد کتابخانه Material UI نوشته شده توسط دیگران کار میکنید و میخواهید کد دقیق هر بخشی از UI را پیدا کنید، این برنامه افزودنی نجاتبخش است.
2. هرگز URL API را در برنامه هاردکد قرار ندهید
هر زمان که یک تماس API برقرار می کنید، هرگز URL API را کد سخت نکنید، در عوض، ایجاد کنید src/utils/constants.js
یا یک فایل مشابه و اضافه کنید API URL
داخل آن به این صورت:
export const BASE_API_URL = "https://jsonplaceholder.typicode.com";
و هر جا که میخواهید یک تماس API برقرار کنید، فقط از آن ثابت با استفاده از نحو تحت اللفظی الگو مانند زیر استفاده کنید:
// posts.jsx
import { BASE_API_URL } from '../utils/constants.js';
const {data} = await axios.get(`${BASE_API_URL}/posts`);
// users.jsx
import { BASE_API_URL } from '../utils/constants.js';
const {data} = await axios.get(`${BASE_API_URL}/users`);
و با این تغییر، اگر بعداً خواستید آن را تغییر دهید BASE_API_URL
مقدار، پس نیازی به تغییر آن در چندین فایل ندارید.
فقط باید آن را در قسمت آپدیت کنید constants.js
فایل، در همه جا منعکس خواهد شد.
PS: شما حتی می توانید ذخیره کنید BASE_API_URL
ارزش در .env
فایل به جای ذخیره آن در constants.js
فایل تا بتوانید به راحتی آن را بسته به محیط توسعه یا تولید تغییر دهید.
3. از صادرات بشکه برای سازماندهی اجزای واکنش استفاده کنید
وقتی روی یک پروژه بزرگ React کار می کنید، ممکن است چندین پوشه حاوی اجزای مختلف داشته باشید.
در چنین مواردی، اگر از اجزای مختلف در یک فایل خاص استفاده میکنید، فایل شما حاوی عبارات وارداتی زیادی مانند زیر است:
import ConfirmModal from './components/ConfirmModal/ConfirmModal';
import DatePicker from './components/DatePicker/DatePicker';
import Tooltip from './components/Tooltip/Tooltip';
import Button from './components/Button/Button';
import Avatar from './components/Avatar/Avatar';
که ظاهر خوبی ندارد زیرا با افزایش تعداد اجزاء، تعداد اظهارنامه های واردات نیز افزایش می یابد.
برای رفع این مشکل، می توانید یک index.js
فایل در پوشه والد (components)
پوشه کنید و تمام کامپوننت ها را به صورت صادراتی با نام از آن فایل مانند زیر صادر کنید:
export { default as ConfirmModal } from './ConfirmModal/ConfirmModal';
export { default as DatePicker } from './DatePicker/DatePicker';
export { default as Tooltip } from './Tooltip/Tooltip';
export { default as Button } from './Button/Button';
export { default as Avatar } from './Avatar/Avatar';
این کار فقط یک بار باید انجام شود. اکنون، اگر در هر یک از فایل ها می خواهید به هر مؤلفه ای دسترسی داشته باشید، می توانید به راحتی آن را با استفاده از import نامگذاری شده در یک خط مانند زیر وارد کنید:
import {ConfirmModal, DatePicker, Tooltip, Button, Avatar} from './components';
که همان است
import {ConfirmModal, DatePicker, Tooltip, Button, Avatar} from './components/index';
این یک روش استاندارد هنگام کار بر روی پروژه های صنعتی/شرکتی بزرگ است.
این الگو به عنوان الگوی بشکه ای شناخته می شود که یک الگوی سازماندهی فایل است که به ما امکان می دهد همه ماژول ها را در یک فهرست از طریق یک فایل واحد صادر کنیم.
در اینجا یک نسخه ی نمایشی CodeSandbox وجود دارد تا آن را در عمل ببینید.
4. ذخیره کلید API در فایل .env در React Application آن را خصوصی نکنید
اگر از a استفاده می کنید .env
فایل برای ذخیره اطلاعات خصوصی مانند API_KEY
در برنامه React شما، در واقع آن را خصوصی نمی کند.
برنامه React شما در سمت کلاینت/مرورگر اجرا میشود، بنابراین هر کسی همچنان میتواند آن را ببیند API_KEY
به عنوان بخشی از استفاده می شود API URL
از تب شبکه
راه بهتر برای خصوصی کردن آن، ذخیره آن در قسمت پشتیبان است.
توجه داشته باشید که، حتی با استفاده از .env
فایل درون React حفظ حریم خصوصی مطلق را تضمین نمی کند، توصیه می شود این روش را برای یک لایه امنیتی بیشتر دنبال کنید.
بنابراین هیچ کس نمی تواند آن را پیدا کند API_KEY
مستقیماً در کد منبع برنامه شما.
همچنین، مطمئن شوید که فشار ندهید .env
به دلایل امنیتی در GitHub قرار دهید. می توانید با اضافه کردن آن به آن به آن دست پیدا کنید .gitignore
فایل
5. ارسال یک کلید متفاوت به کامپوننت باعث ایجاد مجدد کامپوننت می شود
<BookForm
key={book.id}
book={book}
handleSubmit={handleSubmit}
/>
هر زمان که کلید دیگری را به کامپوننت می دهیم، کامپوننت دوباره ایجاد می شود و تمام داده ها و وضعیت آن بازنشانی می شود.
این گاهی اوقات مفید است اگر نمی خواهید اطلاعات قبلی را حفظ کنید / وضعیت مؤلفه را پس از مدتی بازنشانی کنید.
به عنوان مثال، در یک صفحه واحد، مدال های مختلفی را برای نمایش اطلاعات مختلف باز می کنید، سپس می توانید یک کلید منحصر به فرد را برای هر مدال ارسال کنید، بنابراین هر بار که مدال را باز می کنید، اطلاعات قبلی حفظ نمی شود و می توانید برای نمایش داده های مودال صحیح مربوطه.
بنابراین این یکی از دلایلی است که شما به یک کلید منحصر به فرد نیاز دارید که در حین استفاده از روش نقشه آرایه در حین رندر مجدد تغییر نکند.
زیرا هر زمان که کلید تغییر کند، React آن عنصر و تمام عناصر فرزند آن از جمله مؤلفههایی را که درون آن عنصر والد قرار دادهاید، دوباره ایجاد میکند و باعث مشکلات عملکردی عمده میشود.
6. با ایجاد پوشه های جداگانه برای هر یک، اجزا را سازماندهی کنید
هر زمان که کامپوننتی را ایجاد میکنید، آن مؤلفه را مستقیماً در پوشه مؤلفهها قرار ندهید.
در عوض، پوشههای مجزا برای اجزای جداگانه در داخل پوشه کامپوننتها مانند این ایجاد کنید:
--- components
--- header
--- Header.jsx
--- Header.css
--- Header.test.js
--- footer
--- Footer.jsx
--- Footer.css
--- Footer.test.js
--- sidebar
--- Sidebar.jsx
--- Sidebar.css
--- Sidebar.test.js
همانطور که در بالا می بینید، ما یک را ایجاد کرده ایم header
،footer
، و sidebar
پوشه های داخل components
پوشه، و در داخل header
پوشه، تمام فایل های مربوط به header
نگهداری می شوند.
در مورد هم همینطور است footer
و sidebar
پوشه ها
7. از Redux برای هر برنامه React استفاده نکنید
هنگام ساختن یک برنامه React در ابتدا از خود Redux استفاده نکنید.
برای برنامه های کوچکتر استفاده از React Context API یا useReducer hook برای مدیریت برنامه React کافی است.
در زیر برخی از موارد استفاده وجود دارد که می توانید Redux را انتخاب کنید.
برای مدیریت وضعیت جهانی: هنگامی که یک وضعیت برنامه جهانی مانند احراز هویت، اطلاعات نمایه یا داده ای دارید که باید بین چندین مؤلفه به اشتراک گذاشته شود.
برای به اشتراک گذاشتن داده ها بین اجزای غیر مرتبط: زمانی که برنامه شما دارای چندین صفحه با استفاده از مسیریابی است، و بنابراین نمیتوانید حالت مولفه والد را بالا ببرید
به روز رسانی های ایالتی ثابت: Redux یک منبع از حقیقت را برای وضعیت برنامه شما اعمال می کند و به روز رسانی و حفظ وضعیت برنامه شما را به شیوه ای ثابت آسان تر می کند.
مقیاس پذیری: Redux میتواند با ارائه یک الگوی واضح برای مدیریت وضعیت با افزایش اندازه و پیچیدگی برنامه شما، به مقیاس برنامه شما کمک کند.
برای یادگیری Redux + Redux Toolkit از ابتدا می توانید این دوره را دنبال کنید.
8. از روش console.count برای پیدا کردن تعداد رندرهای مجدد کامپوننت استفاده کنید
گاهی اوقات می خواهیم بدانیم که یک خط کد خاص چند بار اجرا می شود.
شاید بخواهیم بدانیم یک تابع خاص چند بار اجرا می شود.
در این صورت می توانیم از a استفاده کنیم console.count
روش با ارسال یک رشته منحصر به فرد به عنوان آرگومان.
به عنوان مثال، اگر یک کد React دارید و می خواهید بفهمید که چند بار کامپوننت دوباره رندر می شود، به جای اضافه کردن console.log
و با شمارش دستی تعداد دفعاتی که در کنسول چاپ شده است، فقط می توانید اضافه کنید console.count('render')
در جزء
و پیام رندر را به همراه تعداد دفعات اجرا مشاهده خواهید کرد.
9. از اعلام وضعیت جدید برای ذخیره همه چیز در داخل یک کامپوننت خودداری کنید
قبل از اعلام وضعیت جدید در یک جزء، همیشه دو بار فکر کنید اگر واقعاً نیاز دارید که آن اطلاعات را در حالت ذخیره کنید.
زیرا هنگامی که یک متغیر حالت را اعلام کردید، باید فراخوانی کنید setState
برای بهروزرسانی مقدار حالت، و هر زمان که وضعیت تغییر کند، React مؤلفهای که آن حالت را دارد و همچنین تمام مؤلفههای مستقیم و غیرمستقیم فرزند آن را دوباره ارائه میکند.
بنابراین با معرفی یک حالت واحد، یک رندر مجدد اضافی در برنامه خود اضافه می کنید، و اگر برخی از مؤلفه های فرزند سنگین دارید که فیلتر، مرتب سازی یا دستکاری داده های زیادی را انجام می دهند، به روز رسانی رابط کاربری با تغییرات جدید زمان بیشتری می برد. .
اگر فقط نیاز دارید مقداری را ردیابی کنید که به هیچ جزء فرزندی منتقل نمیکنید یا در حین رندر استفاده نمیکنید، از هوک useRef برای ذخیره آن اطلاعات استفاده کنید.
زیرا به روز رسانی مقدار ref باعث رندر مجدد کامپوننت نمی شود.
10. هر عملکردی را در داخل یک جزء اعلام نکنید
هنگامی که یک تابع را در داخل یک کامپوننت اعلام می کنید، اگر آن تابع به وضعیت یا اجزای کامپوننت بستگی ندارد، آن را خارج از کامپوننت اعلام کنید.
زیرا در هر رندر مجدد کامپوننت، همه توابع در کامپوننت عملکردی دوباره ایجاد میشوند، بنابراین اگر توابع زیادی در یک جزء دارید، ممکن است برنامه را کند کند.
به کد زیر دقت کنید:
const getShortDescription = (description) => {
return description.slice(0, 20);
}
تابع فوق هیچ گونه وابستگی به حالت یا مقدار prop ندارد.
ما فقط یک مقدار را برای دریافت متن کوتاه شده ارسال می کنیم. بنابراین نیازی به اعلام آن در داخل کامپوننت نیست.
همچنین، اگر به عملکرد توصیف کوتاه یکسان در اجزای مختلف نیاز دارید، به جای تکرار کد در آن اجزا، تابع را به فایل دیگری مانند utils/functions.js
و آن را از آنجا صادر کنید و در اجزای مورد نیاز استفاده کنید.
این باعث می شود اجزای شما به راحتی قابل درک باشند.
11. برنامه های React خود را حداقل به نسخه 18 ارتقا دهید
با React نسخه 18، عملکرد برنامه بهتری در مقایسه با نسخه کمتر از 18 دارید.
با نسخه 18، React بهروزرسانیهای چند حالت را در یک چرخه رندر واحد جمع میکند. بنابراین اگر چندین تماس حالت تنظیم شده در تابعی مانند زیر دارید:
const handleUpdate = (user) => {
setCount(count => count + 1);
setIsOpen(open => !open);
setUser(user);
}
سپس فقط به دلیل وجود سه تماس به روز رسانی حالت، React کامپوننت را سه بار دوباره رندر نمی کند، در عوض، تنها یک بار رندر می شود.
در نسخه React کمتر از 18، فقط بهروزرسانیهای حالت در داخل توابع مدیریت رویداد با هم جمع میشوند، اما بهروزرسانیها در داخل قرار میگیرند. promises
، setTimeout
تابع، کنترلکنندههای رویداد بومی یا هر کنترلکننده رویداد دیگری دستهبندی نمیشوند.
اگر از نسخه React کمتر از 18 استفاده می کنید، برای کد بالا، چون سه حالت به روز رسانی وجود دارد، کامپوننت سه بار رندر می شود که عملکرد ناکارآمدی دارد.
با نسخه 18، به روز رسانی ها را در داخل قرار دهید timeouts
، promises
، کنترل کننده های رویداد بومی یا هر رویداد دیگری با هم جمع می شوند، بنابراین برای کد بالا، ارائه کد فقط یک بار اتفاق می افتد.
12. از محل صحیح برای راه اندازی QueryClient در Tanstack Query/React Query استفاده کنید
هنگام استفاده از Tanstack Query / React Query، هرگز ایجاد نکنید QueryClient
نمونه داخل کامپوننت
را QueryClient
Query Cache را نگه می دارد، بنابراین اگر یک کلاینت جدید در داخل یک جزء ایجاد می کنید، با استفاده از کد زیر:
const queryClient = new QueryClient();
سپس در هر رندر مجدد مؤلفه، یک کپی جدید از کش کوئری دریافت خواهید کرد. بنابراین داده های پرس و جو شما در حافظه پنهان ذخیره نمی شوند و عملکرد ذخیره سازی آن طور که انتظار می رود کار نخواهد کرد.
پس همیشه خلق کنید QueryClient
نمونه خارج از کامپوننت به جای داخل کامپوننت.
// Instead of writing code like this:
const App = () => {
// ❌ Dont' create queryClient inside component. This is wrong.
const queryClient = new QueryClient();
return (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
}
// write it like this:
// ✅ This is correct place to create queryClient
const queryClient = new QueryClient();
const App = () => {
return (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
}
اگر می خواهید React Query / Tanstack Query را از ابتدا یاد بگیرید، این دوره را بررسی کنید.
13. از پسوند ReacTree VSCode برای یافتن روابط فرزند والدین استفاده کنید
از پسوند ReacTree VS Code برای مشاهده سریع نمای درختی اجزای برنامه React خود استفاده کنید.
این یک راه عالی برای پیدا کردن روابط اجزای والدین و فرزند است.
14. همیشه هنگام کار با فرم ها از کتابخانه هایی مانند react-hook-form استفاده کنید
هر زمان که با فرمهای ساده و همچنین پیچیده در React کار میکنم، من همیشه کتابخانه react-hook-form را ترجیح میدهم که محبوبترین کتابخانه مرتبط با فرم React است.
از ref به جای حالت برای مدیریت داده های ورودی استفاده می کند که به جلوگیری از مشکلات عملکرد در برنامه کمک می کند.
با استفاده از این کتابخانه، کامپوننت شما روی هر کاراکتر تایپ شده مجدداً رندر نمیشود، در صورتی که خودتان آن را با حالت مدیریت کنید.
شما همچنین از مزیت افزوده روشی آسان برای اجرای اعتبارسنجی واکنشی برای فرم های خود بهره مند می شوید.
همچنین کد کامپوننت شما را بسیار ساده تر و قابل فهم تر می کند.
این یک کتابخانه بسیار قدرتمند است، بنابراین حتی کتابخانه shadcn/ui از آن برای مؤلفه Form خود استفاده می کند.
اگر می خواهید react-hook-form را از ابتدا یاد بگیرید، این مقاله را بررسی کنید.
15. از انتقال تابع setState به عنوان پشتوانه برای اجزای کودک خودداری کنید
هرگز تابع setState را مستقیماً به عنوان یک پایه به هیچ یک از مؤلفه های فرزند مانند زیر منتقل نکنید:
const Parent = () => {
const [state, setState] = useState({
name: '',
age: ''
})
.
.
.
return (
<Child setState={setState} />
)
}
وضعیت یک جزء باید فقط توسط خود آن جزء تغییر کند.
در اینجا چرا:
-
این تضمین می کند که کد شما قابل پیش بینی است. اگر setState را مستقیماً به چندین مؤلفه منتقل کنید، تشخیص اینکه وضعیت از کجا تغییر می کند دشوار خواهد بود.
-
این عدم قابلیت پیش بینی می تواند منجر به رفتار غیرمنتظره شود و اشکال زدایی کد را دشوار کند.
-
با گذشت زمان، همانطور که برنامه شما رشد می کند، ممکن است لازم باشد نحوه مدیریت حالت را در مؤلفه والد تغییر دهید یا تغییر دهید.
-
اگر مؤلفههای فرزند به دسترسی مستقیم به setState متکی باشند، این تغییرات میتوانند در پایگاه کد موج بزنند و به بهروزرسانیها در مکانهای مختلف نیاز داشته باشند و خطر ایجاد اشکالات را افزایش دهند.
-
اگر دادههای حساس بخشی از حالت باشند، انتقال مستقیم setState میتواند به طور بالقوه آن دادهها را در معرض مؤلفههای فرزند قرار دهد و خطرات امنیتی را افزایش دهد.
-
الگوریتم تطبیق مولفههای React زمانی کارآمدتر عمل میکند که بهروزرسانیهای حالت و props به وضوح در داخل مؤلفهها تعریف شده باشند.
به جای عبور setState
به طور مستقیم می توانید کارهای زیر را انجام دهید:
داده ها را به عنوان ابزار ارسال کنید: دادههایی را که مؤلفه فرزند به آن نیاز دارد، بهعنوان پروپوزال ارسال کنید، نه خود تابع setState. به این ترتیب، یک رابط واضح برای مؤلفه فرزند فراهم میکنید تا دادهها را بدون افشای جزئیات پیادهسازی وضعیت دریافت کند.
عملکرد پاس به عنوان پایه: اگر مؤلفه فرزند نیاز به تعامل با وضعیت مؤلفه والد داشته باشد، میتوانید تابعی را به عنوان یک پایه ارسال کنید. یک تابع را در کامپوننت والد اعلام کنید و وضعیت را در آن تابع به روز کنید، می توانید این تابع را به عنوان یک پایه به کامپوننت فرزند منتقل کنید و در صورت نیاز آن را از کامپوننت فرزند فراخوانی کنید.
16. از استفاده از اپراتورهای سه تایی تو در تو خودداری کنید
هنگام استفاده از عملگر سه تایی هرگز از یک شرط فراتر نروید و از نوشتن شرایط تودرتو خودداری کنید.
// Good Practice
{isAdmin ? <Dashboard /> : <Profile /> }
// Bad Practice
{isAdmin ? <Dashboard /> : isSuperAdmin ? <Settings /> : <Profile />}
استفاده از شرایط تو در تو در هنگام استفاده از اپراتور سه تایی خواندن و نگهداری کد را دشوار می کند، حتی اگر از فرمت کننده ای برای قالب بندی کد استفاده می کنید.
اگر بیش از یک شرط برای بررسی دارید، می توانید از if/else یا switch case یا lookup map استفاده کنید اما هرگز از عملگر سه تایی مانند زیر استفاده نکنید:
if (isAdmin) {
return <Dashboard />;
} else if (isSuperAdmin) {
return <Settings />;
} else {
return <Profile />;
}
// OR
switch (true) {
case isAdmin:
return <Dashboard />;
case isSuperAdmin:
return <Settings />;
default:
return <Profile />;
}
// OR
{isAdmin && <Dashboard />}
{isSuperAdmin && <Settings />}
{!isAdmin && !isSuperAdmin && <Profile />}
// OR use a lookup map like this:
const data = {
isAdmin: <Dashboard />,
isSuperAdmin: Settings />,
Neither: <Profile />
}
// and access the data using data['isAdmin'],
// resulting in the Dashboard page being displayed.
این نه تنها برای React بلکه در مورد جاوا اسکریپت و سایر زبان های برنامه نویسی نیز صدق می کند.
17. برای هر جزء فایل جداگانه ایجاد نکنید
لازم نیست هر جزء را در یک فایل جداگانه ایجاد کنید.
اگر مؤلفهای دارید که فقط در یک فایل خاص استفاده میشود و آن مؤلفه فقط حداقل کد JSX را برمیگرداند، میتوانید آن مؤلفه را در همان فایل ایجاد کنید.
این کار از ایجاد غیرضروری فایلهای اضافی جلوگیری میکند و همچنین به درک بهتر کد زمانی که در یک فایل است کمک میکند.
const ProfileDetailsHeader = () => {
return (
<header>
<h1 className='text-3xl font-bold leading-10'>
Profile Details
</h1>
<p className='mt-2 text-base leading-6 text-neutral-500'>
Add your details to create a personal touch to your profile.
</p>
</header>
);
};
const Profile = () => {
return (
<ProfileDetailsHeader />
...
<ProfileDetailsFooter />
);
}
18. هرگز اطلاعات خصوصی را مستقیماً در کد ذخیره نکنید
من افراد زیادی را دیده ام که مستقیماً اطلاعات خصوصی خود را مانند پیکربندی Firebase در کدی مانند این می نویسند:
const config = {
apiKey: 'AIdfSyCrjkjsdscbbW-pfOwebgYCyGvu_2kyFkNu_-jyg',
projectId: 'seventh-capsule-78932',
...
};
هرگز این کار را انجام نده این یک مسئله امنیتی مهم است. وقتی فایلی با این پیکربندی را به GitHub فشار میدهید، وقتی شخصی مخزن شما را شبیهسازی میکند، میتواند مستقیماً به دادههای Firebase شما دسترسی داشته باشد.
آنها می توانند داده ها را از Firebase شما اضافه، ویرایش یا حذف کنند.
برای جلوگیری از این مشکل، می توانید یک فایل با نام ایجاد کنید .env
در پروژه خود و برای هر ویژگی شی config، یک متغیر محیطی مانند زیر ایجاد کنید:
// If using Vite.js
VITE_APP_API_KEY=AIdfSyCrjkjsdscbbW-pfOwebgYCyGvu_2kyFkNu_-jyg
// access it as import.meta.env.VITE_APP_API_KEY
// If using create-react-app
REACT_APP_API_KEY=AIdfSyCrjkjsdscbbW-pfOwebgYCyGvu_2kyFkNu_-jyg
// and access it as process.env.REACT_APP_API_KEY
همچنین، اضافه کنید .env
ورود فایل به .gitignore
فایل بنابراین به GitHub منتقل نمی شود.
19. همیشه منطق تجاری مؤلفه خود را به قلاب های سفارشی منتقل کنید
در صورت امکان، همیشه سعی کنید از قلاب های سفارشی حداکثر استفاده را ببرید.
همیشه همه منطق تجاری مؤلفه خود و فراخوانی های API را در یک هوک سفارشی قرار دهید.
به این ترتیب کد کامپوننت شما تمیز و قابل درک، نگهداری و آزمایش به نظر می رسد.
const ResetPassword = () => {
const { isPending, sendResetEmail, error } = useResetPassword();
// some JSX
}
20. هر استفاده از هوک سفارشی یک نمونه جدید ایجاد می کند
اکثر توسعه دهندگان React مبتدی این اشتباه را هنگام درک قلاب های سفارشی مرتکب می شوند.
هنگام استفاده از یک قلاب سفارشی خاص در چندین مؤلفه، ممکن است فکر کنید که هر مؤلفه به دادههای مشابهی که از آن قلاب بازگردانده شده است به شرح زیر اشاره میکند:
const [show, toggle] = useToggle();
با این حال، این مورد نیست.
هر جزء با استفاده از آن قلاب یک نمونه جداگانه از قلاب خواهد داشت.
در نتیجه، همه حالتها، کنترلکنندههای رویداد و سایر دادههای اعلامشده در آن هوک سفارشی برای هر جزء که از آن قلاب استفاده میکند متفاوت خواهد بود.
بنابراین اگر نیاز به استفاده از دادهها و کنترلکنندههای رویداد یکسان برای همه مؤلفهها دارید، باید قلاب سفارشی را تنها در یک مکان در مؤلفه اصلی همه این مؤلفهها وارد کنید.
سپس، میتوانید دادههای بازگردانده شده توسط هوک سفارشی را به عنوان یک پایه ارسال کنید یا از Context API برای دسترسی به آن از اجزای خاص استفاده کنید.
بنابراین هرگز با استفاده از یک هوک سفارشی در اجزای مختلف اشتباه نکنید، با این فرض که تغییر دادههای هوک از یک مؤلفه بهطور خودکار در مؤلفه دیگر نیز بهروزرسانی میشود.
در اینجا یک نسخه ی نمایشی CodeSandbox وجود دارد تا آن را در عمل ببینید.
21. از از دست دادن ویژگی های حالت هنگام به روز رسانی اشیا با React Hook جلوگیری کنید
هنگام استفاده از اجزای کلاس، اگر حالتی با چندین ویژگی مانند این دارید:
state = {
name: '',
isEmployed: false
};
سپس برای به روز رسانی حالت می توانیم فقط ویژگی را که می خواهیم به روز رسانی کنیم به این صورت مشخص کنیم:
this.setState({
name: 'David'
});
// OR
this.setState({
isEmployed: true
});
بنابراین سایر ویژگی های حالت هنگام به روز رسانی هیچ ویژگی از بین نخواهند رفت.
اما هنگام کار با قلاب های React، اگر حالت یک شی مانند زیر ذخیره می کند:
const [state, setState] = useState({
name: '',
isEmployed: false
});
سپس هنگام بهروزرسانی یک ویژگی حالت خاص، بهصورت دستی باید ویژگیهای قبلی را مانند این پخش کنید:
setState((prevState) => {
return {
...prevState,
name: 'David'
};
});
// OR
setState((prevState) => {
return {
...prevState,
isEmployed: true
};
});
اگر مقادیر حالت قبلی را پخش نکنید، سایر ویژگی ها از بین خواهند رفت.
زیرا هنگام استفاده از حالت به طور خودکار ادغام نمی شود useState
قلاب با شی
22. افزودن دینامیک کلاس های Tailwind در React کار نمی کند
اگر از Tailwind CSS برای استایلسازی استفاده میکنید و میخواهید به صورت پویا هر کلاسی را اضافه کنید، کد زیر کار نخواهد کرد.
<div className={`bg-${isActive ? 'red-200' : 'orange-200'}`}>
Some content
</div>
این به این دلیل است که در فایل CSS نهایی شما، Tailwind CSS فقط شامل کلاسهایی است که در طول اسکن اولیه فایل شما وجود دارد.
بنابراین کد بالا به صورت پویا اضافه می کند bg-red-200
یا bg-orange-200
کلاس به div اما CSS آن اضافه نخواهد شد بنابراین CSS اعمال شده روی آن div را نخواهید دید.
بنابراین برای رفع این مشکل، ابتدا باید کل کلاس را به صورت زیر تعریف کنید:
<div className={`${isActive ? 'bg-red-200' : 'bg-orange-200'}`}>
Some content
</div>
اگر کلاسهای زیادی دارید که باید به صورت شرطی اضافه شوند، میتوانید یک شی را با نامهای کلاس کامل مانند این تعریف کنید:
const colors = {
purple: 'bg-purple-300',
red: 'bg-red-300',
orange: 'bg-orange-300',
violet: 'bg-violet-300'
};
و به این صورت از آن استفاده کنید:
<div className={colors['red']}>
Some content
</div>
23. هنگام استفاده از روتر React، همیشه مسیر صفحه پیش فرض یا یافت نشد را اضافه کنید
هر زمان که با استفاده از روتر React مسیریابی را در React پیاده سازی می کنید، فراموش نکنید که یک مسیر برای یک مسیر نامعتبر (صفحه یافت نشد) اضافه کنید.
زیرا اگر شخصی به مسیری که وجود ندارد پیمایش کند، یک صفحه خالی می بیند.
برای راه اندازی یک مسیر نامعتبر، می توانید جزء مسیر نامعتبر را به عنوان آخرین مسیر در لیست مسیرها مانند شکل زیر ذکر کنید.
<Routes>
<Route path="/" element={<Home />} />
.
.
.
<Route path="*" element={<NotFoundPage />} />
</Routes>
اگر نمیخواهید مؤلفه NotFoundPage را برای یک مسیر نامعتبر نمایش دهید، میتوانید تغییر مسیر را طوری تنظیم کنید که به صورت خودکار به صفحه اصلی مسیر نامعتبر مانند شکل زیر هدایت شود.
<Routes>
<Route path="/" element={<Home />} />
.
.
.
<Route path="*" element={<Navigate to="/" />} />
</Routes>
24. از Spread Operator برای انتقال آسان ویژگی های شی به کامپوننت فرزند استفاده کنید
اگر وسایل زیادی دارید که باید به یک کامپوننت ارسال شوند، بهجای اینکه موارد منفرد را مانند این ارسال کنید:
const Users = ({users}) => {
return (
<div>
{users.map(({ id, name, age, salary, isMarried }) => {
return (
<User
key={id}
name={name}
age={age}
salary={salary}
isMarried={isMarried}
/>
)
})}
</div>
)
}
شما می توانید از عملگر spread برای عبور آسان پروپ های مانند زیر استفاده کنید:
const Users = ({users}) => {
return (
<div>
{users.map((user) => {
return (
<User key={user.id} {...user} />
)
})}
</div>
)
}
با این حال، از این نحو گسترش بیش از حد استفاده نکنید. اگر شیئی که در حال پخش آن هستید دارای خواص زیادی است، ارسال آنها به صورت دستی همانطور که در کد اول نشان داده شده است بهتر از پخش کردن است.
25. انتقال حالت به هوک سفارشی، مولفه را از رندر مجدد باز نمی دارد
هر زمان که از هر قلاب سفارشی در هر یک از مؤلفه ها استفاده می کنید و اگر وضعیت داخل آن قلاب سفارشی تغییر کند، مؤلفه ای که از آن قلاب سفارشی استفاده می کند دوباره رندر می شود.
به کد زیر دقت کنید:
export const useFetch = () => {
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(false);
// some code to fetch and update data
return { data, isLoading };
};
const App = () => {
const { data, isLoading } = useFetch();
// return some JSX
};
همانطور که در کد بالا مشاهده می شود، useFetch
یک قلاب سفارشی است بنابراین هر زمان که data
یا isLoading
تغییر حالت، App
کامپوننت دوباره رندر می شود.
بنابراین اگر App
مؤلفه در حال رندر کردن برخی مؤلفه های فرزند دیگر است، آن فرزند مستقیم و همچنین مؤلفه های فرزند غیرمستقیم نیز هنگامی که data
یا isLoading
ایالت از useFetch
تغییرات قلاب سفارشی
بنابراین فقط به این دلیل که شما آن را بازسازی کرده اید App
حالت حرکت جزء در داخل قلاب سفارشی به این معنی نیست که App
کامپوننت دوباره رندر نمی شود.
با تشکر برای خواندن!
آیا می خواهید با محتوای معمولی مربوط به جاوا اسکریپت، React و Node.js به روز بمانید؟ من را در لینکدین دنبال کنید.
اشتراک مادام العمر / حرفه ای را دریافت کنید
Master JavaScript، React و Node.js
در کانال یوتیوب من مشترک شوید
GitHub من