<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های مصطفی رحمتی</title>
        <link>https://virgool.io/feed/@M.Rahmati</link>
        <description>FrontEnd Developer (Javascript/ReactJS/NextJS)</description>
        <language>fa</language>
        <pubDate>2026-06-07 19:36:26</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/26545/avatar/NE5InF.jpg?height=120&amp;width=120</url>
            <title>مصطفی رحمتی</title>
            <link>https://virgool.io/@M.Rahmati</link>
        </image>

                    <item>
                <title>10 روش‌ مؤثر برای سازماندهی و طراحی بهتر برنامه‌های React</title>
                <link>https://virgool.io/@M.Rahmati/10-%D8%B1%D9%88%D8%B4-%D9%85%D8%A4%D8%AB%D8%B1-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%B3%D8%A7%D8%B2%D9%85%D8%A7%D9%86%D8%AF%D9%87%DB%8C-%D9%88-%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%D8%A8%D9%87%D8%AA%D8%B1-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%87%D8%A7%DB%8C-react-b8sld436c2jh</link>
                <description>قبل از شروع، بر خود لازم می‌دانم به این نکته اشاره کنم که این مقاله ترجمه شده (همراه با بازنویسی و اقتباس) از مقاله‌ای دیگر است. بنابراین اگر خواندن مقاله تخصصی به زبان فارسی برای شما راحت نیست یا خواندن مقاله تخصصی به زبان انگلیسی برایتان جذاب‌تر است، می‌توانید به منبع اصلی این مقاله مراجعه کنید.این تصویر با استفاده از هوش مصنوعی ایجاد شده استمقدمهزمانی که تصمیم دارید یک برنامه ری‌اکتی را توسعه دهید، نحوه کانفیگ و سازماندهی آن برنامه از اهمیت قابل توجهی برخوردار است؛ به‌طوری‌که می‌تواند به ما و تیم‌مان کمک کند تا به راحتی موارد مورد نیاز را پیدا کنیم، توسعه و بروزرسانی‌ها سریع‌تر انجام شود یا حتی همه چیز را بدتر کند (با توجه به اینکه کانفیگ و سازماندهی اصولی یا غیر اصولی انجام شده باشد).این اصل دقیقاً در ساختمان‌سازی هم وجود دارد. اگر پایه‌ها به درستی گذاشته و موارد اصولی نیز به‌درستی رعایت شده باشند، آن ساختمان می‌تواند مدت طولانی‌تری دوام و استقامت داشته باشد، در غیر این صورت ممکن است ساختمان فرو بپاشد و همه چیز از بین برود.پایه‌های ناپایدار منجر به نتایج ناپایدار می‌شوند.فهرست مطالبگروه‌بندی کامپوننت‌ها بر اساس مسئولیت‌های آنقرار دادن کامپوننت‌ها در فولدر جداگانهاستفاده از مسیردهی مطلق (Absolute Paths)استفاده از common module هااز کتابخانه‌ها و ماژول‌های خارجی انتزاع ایجاد کنیدمدیریت وابستگی‌ها بین ماژول‌ها/صفحاتنگه داشتن اجزا در نزدیکی جایی که استفاده می‌شوند (اصل هم‌جواری رفتار یا LoB)دقت در استفاده از Utility Function هااستفاده هوشمندانه از Business Logicثابت نگه داشتن وابستگی‌ها1. گروه‌بندی کامپوننت‌ها بر اساس مسئولیت‌ آن‌هاسازماندهی فایل‌ها و فولدرها در یک برنامه React برای حفظ نگه‌داری و قابلیت مدیریت آن بسیار مهم و حیاتی است. هر چه پیمایش و جابجایی در پروژه آسان‌تر و کمتر باشد، زمان کمتری برای توسعه‌دهندگان صرفِ جستجو و تعجبْ از این‌که کجا و چگونه باید تغییرات را اعمال کنند، صرف خواهد شد.مهم است که فایل‌ها نه تنها بر اساس نقش‌های فنی؛ بلکه بر اساس مسئولیت‌های دامنه آن‌ها نیز ساختاربندی شده باشند.⛔ از گروه‌بندی کامپوننت‌ها صرفاً بر اساس مسئولیت‌های فنی اجتناب کنید/src
│   ...
│
└───components
│    │   Header.js
│    │   Footer.js
│    │   ...
└───containers
│    │   InvoicesContainer.js
│    │   PaymentProfilesContainer.js
│    │   ...
└───presenters
│     │   InvoicesPresenter.js
│     │   PaymentProfilesPresenter.js
│     │   ...
│   ...
✅ بهتر است که کامپوننت‌ها را بر اساس مسئولیت‌های دامنه‌ای مانند مسیر صفحات (routes) یا ماژول‌ها (modules) گروه‌بندی شده باشند./src
│   ...
│
└───pages --&gt; صفحاتی که هر کدام نمایانگر بخش‌های مختلف برنامه هستند
│    └───billing
│    │    └───invoices
│    │    │   │   index.js
│    │    │   │   ...
│    │    └───payment-profiles
│    │    │   │   index.js
│    │    │   │   ...
│    │    │   ...
│    │    │   index.ts
│    └───login
│        │   index.js
│        │   ...
│   ...
2. قرار دادن کامپوننت‌ها در فولدر جداگانهبرای کامپوننت‌های پیچیده، بهتر است آن‌ها را در فولدرهای جداگانه سازماندهی و ایجاد کنیم تا بتوانیم ساب‌کامپوننت‌های (SubComponents) آن‌ها را لیست کنیم.⛔ از داشتن یک فایل برای هر کامپوننت خودداری کنید./src
│
└───components         
│   │   Accordion.ts
|   |   Alert.ts
│   │   ...
│
└───...✅ ترجیحاً برای هر کامپوننت یک دایرکتوری جداگانه ایجاد کنید./src
│
└───components
│   │   ...
│   └───accordion             
│   │    │   index.ts
│   │    │   ...
│   └───alert             
│       │   index.ts
│       │   types.ts
│       │   Alert.tsx
│       │   AlertTitle.tsx
│       │   Alert.stories.tsx
│       │   Alert.test.tsx
│       │   ...
│
└───...مثال برای داشتن دایرکتوری جداگانه برای هر کامپوننت 3. استفاده از مسیردهی مطلق (Absolute Paths)استفاده از نوع مناسب مسیردهی در پروژه می‌تواند پیمایش و نگهداری کد را آسان‌تر کند، به‌ویژه هنگامی که پروژه گسترش پیدا می‌کند. همچنین ری‌فکتور (refactor) پروژه را بسیار راحت‌تر خواهد کرد.⛔ از مسیردهی نسبی (Relative Paths) که در پروژه‌های بزرگ، مدیریت را دشوار و همواره مستعد خطا هستند، خودداری کنید.import { formatDate } from &#039;../../../utils&#039;;✅ ترجیحاً از مسیرهای مطلق (Absolute Paths) که خوانایی کد را بهبود می‌بخشند و بازنگری (refactor) کد را آسان‌تر می‌کنند، استفاده کنید.import { formatDate } from &#039;@common/utils&#039;;4. استفاده از common module هاماژول‌های مشترک (Common module) نقش بسیار مهم و حیاتی در جلوگیری از تکرار کد و افزایش قابلیت استفاده مجدد از کد را در سراسر برنامه، ایفا می‌کنند.می‌توانید متدهای کمکی (utility method)، ثابت‌ها (constants)، کامپوننت‌ها، محاسبات (calculations) و غیره را در این ماژول مشترک نگهداری کنید.این متمرکز سازی به مدیریت بهتر کد و استفاده مجدد از آن کمک می‌کند.⛔ از پراکنده کردن ابزارها و کامپوننت‌های مشترک در مکان‌های مختلف پروژه خودداری کنید.✅ ترجیحاً یک ماژول مشترک اختصاصی برای تمام کامپوننت‌ها و ابزارهای عمومی که در صفحات یا ماژول‌های مختلف استفاده می‌شوند، داشته باشید./src
│   ...
│
└───common
│    └───components
│    │    └───dialogs
│    │    │   │   index.js
│    │    └───forms
│    │    │   │   index.js
│    │    │   ...
│    └───hooks
│    │    │   useDialog.js
│    │    │   useForm.js
│    │    │   ...
│    └───utils
│    │    │   ...
└───pages
│    └───billing
│    │    └───invoices
│    │    │   │   index.js
│    │    │   │   ...
│   ...دیدگاه مترجم:به دو علت استفاده از این ساختار بندی در پروژه‌های فرانت مخالفم:فولدرهایی که در سطح root یا src پروژه قراردارند، (جزء در موارد خاص مانند pages یا features) به طور معمول بیانگر موارد مشترک در کل پروژه هستند و نیازی به جداسازی این موارد در زیر دایرکتوری‌ای تحت عنوان common یا shared نمی‌باشد (مگر اینکه علت استفاده از این ساختار دلیل قانع‌کننده‌ی دیگری داشته باشد).این ساختار باعث ایجاد پیمایش‌های تودرتو می‌شود که نگهداری و دسترسی‌پذیری کد را کاهش می‌دهد.توجه داشته باشید که با استفاده از فولدر common یا shared در سطح root یا src پروژه مخالف هستم، اما ممکن هست که هر دایرکتوری (غالباً در فولدر features) بنا به نیاز خود دارای یک دایرکتوری common یا shared نیز باشد.5. از کتابخانه‌ها و ماژول‌های خارجی انتزاع ایجاد کنیدیکپارچه‌سازی و ادغام کتابخانه‌ها یا ماژول‌های خارجی نیازمند بررسی دقیق است تا از انعطاف‌پذیری در آینده و نگهداری آسان‌ترِ کد، اطمینان حاصل شود.استفاده مستقیم از کتابخانه‌ها یا کامپوننت‌های 3rd party در پروژه می‌تواند منجر به ایجاد مشکلاتی شود؛ اگر API‌های خارجی تغییر کنند یا بخواهید کامپوننت‌ها یا کتابخانه‌ها را با گزینه دیگری جایگزین کنید، باید در تمام مکان‌هایی که از آن‌ها استفاده شده، تغییرات لازم اعمال شوند، به جای آنکه فقط در یک مکان خاص این به‌روزرسانی انجام گردد.محصور کردن (Wrapp) کتابخانه یا ماژول شخص ثالث در یک کامپوننت سفارشی دیگر به ما این امکان را می‌دهد که یک API یکنواخت و یکپارچه در درون برنامه‌ی خود حفظ کنیم و در صورت نیاز در آینده، جایگزین کردن ماژول را با ماژول دیگری آسان‌تر می‌کند.⛔ از استفاده مستقیم از کامپوننت‌ها یا کتابخانه‌های 3rd party در پروژه خود خودداری کنید.// XYZ_Component.ts (file 1)
import { Button } from &#039;react-bootstrap&#039;;

// ABC_Component.ts (file 2)
import { Button } from &#039;react-bootstrap&#039;;✅ ترجیحاً کتابخانه‌ها یا کامپوننت‌های 3rd party را در یک کامپوننت سفارشی دیگر محصور و بسته‌بندی (Wrapp) کنید.// XYZ_Component.ts (file 1)
import { Button } from &#039;@components/ui&#039;;

// ABC_Component.ts (file 2)
import { Button } from &#039;@components/ui&#039;;6. مدیریت وابستگی‌ها بین ماژول‌ها/صفحاتمدیریت هوشمندانه وابستگی‌ها با متمرکزسازی منابع مشترک در یک ماژول مشترک (shared common)، می‌تواند به‌طور قابل‌توجهی قابلیت نگهداری و استفاده مجدد از کد را افزایش دهد.اگر چیزی بیش از یک‌بار در دو یا چند صفحه یا ماژول دیگر استفاده می‌شود، بهتر است آن را به یک ماژول مشترک انتقال دهید.ذخیره‌سازی کامپوننت‌ها یا ابزارهای مشترک در یک ماژول مشترک، نیاز به تکرار کد در بخش‌های مختلف برنامه را از بین می‌برد، که باعث می‌شود کدبیس سبک‌تر و نگهداری آن آسان‌تر شود.همچنین این کار وابستگی‌ها را برای هر ماژول و هر صفحه به‌وضوح مشخص خواهد کرد.7. نگه داشتن اجزا در نزدیکی جایی که استفاده می‌شوند (اصل هم‌جواری رفتار یا LoB)هرچه برای توسعه‌دهنده پیدا کردن یک قطعه کد آسان‌تر و سریع‌تر باشد، بهتر است.اصل هم‌جواری رفتار (Locality of Behavior - LoB) پیشنهاد می‌کند که کدبیس به‌گونه‌ای سازمان‌دهی شود که کامپوننت‌ها، توابع و منابع در نزدیکی محل مورد استفاده‌شان در برنامه قرار گیرند. این استراتژی، معماری modular را ترویج می‌کند که در آن هر بخش از سیستم خودکفا است.این رویکرد خوانایی و نگهداری‌پذیری کد را بهبود می‌بخشد. زمانی که توسعه‌دهندگان روی یک ویژگی (feature) کار می‌کنند، تمام کدهای مرتبط در نزدیکی یکدیگر قرار دارند که فهم و تغییر آن‌ها را آسان‌تر می‌کند. همچنین بار شناختی ردیابی از طریق فایل‌ها و ماژول‌های دور (خارج از دید در یک نگاه) را کاهش می‌دهد./src
│   ...
│
└───common
│    └───components
│    │    │   ...
│    └───hooks
│    │    │   ...
│    └───utils
│    │    │   ...
└───pages
│    └───billing
│    │    └───invoices
│    │    │   │   index.js
│    │    │   │   ...
│    │    └───payment-profiles
│    │    │   │   index.js
│    │    │   │   ...
│    │    └───hooks
│    │    │   │   index.js
│    │    │   │   useInvoices.js
│    │    │   │   usePaymentProfiles.js
│    │    │   │   ...
│    │    └───utils
│    │    │   │   index.js
│    │    │   │   formatAmount.js
│    │    │   │   ...
│   ...اصل محلی‌سازی/هم‌جواری رفتار (LoB) بر اهمیت قرار دادن اجزا به صورت منطقی در همان بخش‌هایی از کد تأکید دارد که آن‌ها استفاده می‌شوند. به عنوان مثال، اگر یک کامپوننت خاص تنها در یک صفحه خاص استفاده می‌شود، بهتر است آن کامپوننت در همان دایرکتوریِ آن صفحه قرار گیرد تا دسترسی و مدیریت آن آسان‌تر شود.8. دقت در استفاده از Utility Function هاتوابع کمکی (Utility function) معمولاً بخش‌های قابل استفاده‌ی مجددِ کدی هستند که به قوانین کسب‌وکار یا منطق برنامه وابسته نیستند. آن‌ها بیشتر به ارائه کمک‌های عمومی در سراسر سیستم می‌پردازند (مانند فرمت تاریخ‌ها، تبدیل نوع داده‌ها و غیره).توابع کمکی باید خالص و هدف‌مند باقی بمانند و بر وظایف عمومی مانند فرمت تاریخ‌ها، تبدیل انواع داده‌ها و غیره تمرکز کنند. ترکیب آن‌ها با منطق کسب‌وکار (business logic) مانند نحوه پردازش داده‌ها یا تصمیم‌گیری‌های خاص کسب‌وکار، می‌تواند این توابع را بیش از حد پیچیده و کمتر قابل استفاده مجدد کند.همچنین، منطق تجاری و قوانین کسب‌وکار معمولاً بیشتر از توابع کمکی تغییر می‌کنند، بنابراین با جدا کردن آن‌ها، نگهداری کلی کد بهبود می‌یابد.⛔ از افزودن منطق کسب‌وکار به Utility function ها خودداری کنید.✅ ترجیحاً منطق کسب‌وکار را به توابع جداگانه منتقل کنید.9. استفاده هوشمندانه از Business Logicادغام مستقیم منطق کسب‌وکار در کامپوننت‌های رابط کاربری (UI) می‌تواند منجر به ایجاد مشکلاتی مانند سخت‌تر شدن تستِ کد و جداسازی نادرست مسئولیت‌ها شود. این امر همچنین می‌تواند منجر به ایجاد کامپوننت‌های حجیم شود که مدیریت و به‌روزرسانی آن‌ها را دشوار می‌کند.در React، هوک‌های سفارشی ابزار بسیار خوبی برای انتزاع و جداسازی منطق کسب‌وکار از کامپوننت‌ها هستند. با استفاده از هوک‌ها، می‌توانید منطق کسب‌وکار را در یک مکان جداگانه کپسوله کنید و رابط کاربری خود را تمیز و متمرکز بر رندرینگ نگه دارید.این جداسازی نه تنها کامپوننت‌های ما را ماژولارتر (modular) و مدیریت آن‌ها را آسان‌تر می‌کند، بلکه قابلیت استفاده مجدد و نگهداری را نیز افزایش می‌دهد⛔ از ترکیب منطق کسب‌وکار با رابط کاربری خودداری کنید.✅ ترجیحاً منطق کسب‌وکار را از رابط کاربری جدا کنید. از هوک‌های سفارشی استفاده کنید.10. ثابت نگه داشتن وابستگی‌هادر مدیریت پروژه‌های جاوااسکریپت، فایل package.json نقش حیاتی و مهمی را ایفا می‌کند. این فایل وابستگی‌های پروژه را تعریف می‌کند؛ یعنی پکیج‌های خارجی‌ای که پروژه برای عملکرد صحیح خود به آن‌ها نیاز دارد. ثابت نگه داشتن این وابستگی‌ها به معنای مشخص کردن نسخه‌های دقیق این پکیج‌ها به‌جای استفاده از بازه‌های نسخه است.با ثابت نگه داشتن وابستگی‌ها، اطمینان حاصل می‌کنید که همه افرادی که روی پروژه کار می‌کنند، همانند نسخه production، از همان نسخه دقیق هر پکیج استفاده می‌کنند و تناقضاتی که ممکن است به دلیل به‌روزرسانی‌های جزئی (minor update) یا پچ‌ها (patch) رخ دهد، از بین می‌رود.⛔ از استفاده از بازه‌های نسخه (version ranges) در فایل package.json خودداری کنید.{
  &amp;quotdependencies&amp;quot: {
    &amp;quotexpress&amp;quot: &amp;quot^4.17.1&amp;quot,
    &amp;quotreact&amp;quot: &amp;quot&gt;=16.8.0&amp;quot
  }
}✅ ترجیحاً از نسخه‌های دقیق در فایل package.json خود استفاده کنید.{
  &amp;quotdependencies&amp;quot: {
    &amp;quotexpress&amp;quot: &amp;quot4.17.1&amp;quot,
    &amp;quotreact&amp;quot: &amp;quot16.8.0&amp;quot
  }
}10 ways to better organize and design your React Application</description>
                <category>مصطفی رحمتی</category>
                <author>مصطفی رحمتی</author>
                <pubDate>Tue, 24 Dec 2024 17:33:33 +0330</pubDate>
            </item>
                    <item>
                <title>ایجاد کامپوننت‌های چندشکلی در ری‌اکت (Polymorphic Component) - بخش دوم</title>
                <link>https://virgool.io/@M.Rahmati/polymorphic-component-in-react-part2-wtbzpgfsxtnx</link>
                <description>Polymorphic React Components With TypeScript - Part 2 خوب تو قسمت قبل یکسری ملزوماتی رو برای پیاده‌سازی یک Polymorphic Component گفتیم، توی این قسمت قراره بیشتر دست به کد بشیم.همونطور که در بخش اول گفتیم اگه بخواییم یک کامپوننت Polymorphic رو بدون Type Safety ایجاد کنیم، مشکل خاصی نداریم، پس از همین بخش شروع می‌کنیم و کم‌کم کامپوننت رو توسعه می‌دیم تا به چیزی که مدنظرمون هست تبدیل بشه.ساده‌ترین روش ایجاد یک کامپوننت Polymorphic به صورت زیر هست: https://gist.github.com/MR-Mostafa/e03a010c438c8e7744e339ac1e28dbfd با استفاده از کد بالا، ما به همین راحتی سه مورد اول از ملزومات پیاده‌سازی یک Polymorphic Component در ری‌اکت رو ایجاد کردیم. اگر یک توضیح مختصری بخوام در خصوص موارد گفته شده بگم، همونطور که مشاهده می‌کنید:1. کامپوننت ما یک پراپس به عنوان as دریافت می‌کند (مورد اول از ملزومات) 2. این پراپرتی تعیین می‌کند که المنتی در DOM  باید رندر شود چه چیزی می‌باشد (مورد دوم از ملزومات) 3. همچنین با استفاده از Rest parameters، کامپوننت ما از سایر اتریبیوت‌ها و ویژگی‌ها پیشتبانی می‌کند. (مورد سوم از ملزومات) https://stackblitz.com/edit/example-polymorphic-step1?embed=1&amp;file=src%2FApp.tsx&amp;hideExplorer=1&amp;hideNavigation=1 احتمالا با مواردی که در بخش قبل گفته شد، می‌تونید حدس بزنید که کامپوننت بالا چه مشکلاتی داره. قبل از برطرف کردن این مشکلات، بهتره اون‌ها رو به صورت شفاف بشناسیم:1- پراپرتی as هر چیزی رو به عنوان ورودی قبول می‌کند، حتی یک HTML المنت غیرمعتبر (تگ mostafa یک HTML المنت غیرمعتبر می‌باشد)HTML المنت غیرمعتبر2- حتی اگر مقدار as یک HTML المنت معتبر باشد، ممکن است اتریبیوت‌های اشتباه وارد شود (اتریبیوت href متعلق به تگ span نمی‌باشد)اتریبیوت اشتباه3- سومین مشکل هم در خصوص forwardRef  هست. اگر کامپوننت ما از این ویژگی پشتیبانی کند، می‌تواند مقدار ref دریافت شده از کامپوننت، خارج از مقدار تعیین شده در تایپ‌اسکریپت باشد. در مثال زیر مقدار ref را یک HTMLButtonElement تعیین کرده‌ایم اما پراپرتی as برابر با تگ span می‌باشد!مقدار ref اشتباهرفع مشکلات گفته شده و Type Safety کردن کامپوننتبرای رفع مشکل ابتدا ما باید به دنبال راه‌حلی باشیم که بتوانیم نوع/تایپ کامپوننت را بر اساس مقدار ورودی اون (همون پراپس as) تعیین کنیم که فقط مقادیری را به عنوان ورودی بپذیرد که یا جزء HTML المنت‌ها معتبر باشند و یا یک کامپوننت ری‌اکتی باشد.اینجاست که Generic‌ها در تایپ‌اسکریپت به کمک ما می‌یان.با Generic ها می‌تونیم کامپوننت (تابع، کلاس‌ و ...)هایی بنویسیم که با نوع‌های داده‌ای مختلفی کار کنن. بجای اینکه کامپوننت‌مون وابسته به یک نوع داده خاص مثلا عددی یا رشته‌ای باشه. (منبع)برای اینکه بتونیم نوع یک المنت رو در ری‌اکت مشخص کنیم باید به سراغ یک Utility Type در ری‌اکت به نام React.ElementType بریم که خودش یک جنریک تایپ هست. https://gist.github.com/MR-Mostafa/6bec49dbc1d26e791cf2044260563480 همانطور که در کد بالا در خط 8 مشاهده می‌کنید، برای تعیین نوع جنریک تایپ (یعنی C) از کلید واژه extends استفاده کرده‌ایم که این بدین معناست که C باید یک نوع (type) معتبر برای React.ElementType باشد. که خودش یک Utility Type برای ری‌اکت است که بیانگر تمامی تگ‌های ولید و معتبر HTML و یا یک کامپوننت ری‌اکتی می‌باشد. (در نتیجه مقدار پراپس as می‌تواند یکی از این دو مورد باشد)در خط 27 نیز مقدار پیش‌فرض المنت رندرشده در DOM را برابر با button قرارداده‌ایم.با انجام این کار، مشکل اول برطرف می‌شه و کامپوننت Polymorphic ما فقط مقادیر مجاز رو قبول می‌کنه.بریم سراغ رفع مشکل دوم، همونطور که در بخش قبلی گفتیم کامپوننت Polymorphic ما باید دارای این ویژگی باشد:کامپوننت باید موارد زیر نیز پشتیبانی کند: (مورد سوم از ملزومات)         -  اتریبیوت‌های سراسری/گلوبال مانند id یا class و ...          - از اتریبیوت‌های مختص با المنت تعیین شده، مانند src در تگ img یا href در تگ a و ...         -  پراپس‌های کاستوم/سفارشی در کامپوننت‌های دیگر یا Third Party؛ مثلا کامپوننت Link در فریم‌ورک NextJs پراپس‌هایی مانند replace یا prefetch و ... را دارد.دقیقا مشکل همینجاست که کامپوننت ما از هیچ اتریبیوتی (چه گلوبال و ...) به صورت Type Safety پشتیبانی نمی‌کنه. مثلا اگر مقدار پراپرس as را برابر با تگ a قرار دهید، طبیعتاً نیاز به اتریبیوت‌های مختص این تگ مانند href, target و ... داریم.{
    as?: C; 
    children: React.ReactNode;
} &amp; {
    ...otherValidPropsBasedOnTheValueOfAs   // ? یک چیزی شبیه به این
}How To Support Other Valid Props, Based On The Value Of Asبرای اینکه این مورد رو برطرف کنیم نیاز هست به سراغ یک Utility Type دیگر از ری‌اکت بریم که عبارتند از:React.ComponentPropsReact.ComponentPropsWithRefReact.ComponentPropsWithoutRefبرای این متوجه بشیم این تایپ‌ها چی هستن و کاربردشون چی هست من از Chat GPT برای پاسخ به این سوال کمک گرفتم، که در ادامه پاسخ Chat GPT رو می‌خونید:در لایبری ReactJS (ری اکت جی اس)، این سه تایپ مربوط به خصوصیت‌ها و پارامترهای ورودی کامپوننت‌ها هستند. البته به صورت استاندارد و در حالت عمومی، معمولاً از نوع طراحی «تایپ اعمال کننده‌ی پارامتر» برای نام‌گذاری این تایپ‌ها استفاده می‌شود.React.ComponentProps:این نوع تایپ برای نام‌گذاری و استفاده از پارامترهای ورودی کامپوننت‌ها استفاده می‌شود. به عبارتی، نوع این تایپ برابر است با نوع خصوصیت‌های پیش‌فرض کامپوننت. در واقع مجموعه‌ای از تمام پارامترهای ورودی کامپوننت را نمایش می‌دهد. این شامل پارامترهای خاصی می‌شود که در کد مورد استفاده مشخص شده است و پارامترهایی که برای کاربرد عمومی هستند (مانند کلاس‌های CSS، رویدادها، و غیره).React.ComponentPropsWithRef:این نوع تایپ نسخه‌ای از React.ComponentProps است که جهت استفاده در کامپوننت‌هایی که قابل استفاده از ref هستند، طراحی شده است. Refs در React به شما اجازه می‌دهند تا به طور مستقیم به عنصر DOM یا کامپوننت‌هایی که به آن تعلق دارند، دسترسی داشته باشید. React.ComponentPropsWithRef شامل پارامترهای ورودی عمومی کامپوننت است و همچنین یک پارامتر ref برای استفاده از ref به صورت ضروری دارد.React.ComponentPropsWithoutRef:این نوع تایپ همچنین نسخه‌ای از React.ComponentProps است، اما برخلاف React.ComponentPropsWithRef، پارامتر ref در آن حذف شده است. این برای استفاده در کامپوننت‌هایی مناسب است که نیازی به دسترسی مستقیم به ref ندارند و این پارامتر برای آن‌ها مورد نیاز نیست.چون در این بخش قصد این رو نداریم که به موضوع Ref بپردازیم، پس به سراغ  React.ComponentPropsWithoutRef می‌ریم و کد قبلی‌مون رو به صورت زیر اصلاح می‌کنیم: https://gist.github.com/MR-Mostafa/f31ec08813dafd4fa6650dedfe7c2a89 الان با استفاده از این Utility Type، ما تنوستیم بخشی از مشکل دوم رو هم برطرف کنیم. به عبارت دیگر کامپوننت Polymorphic ما در حال حاظر از اتریبیوت‌های گلوبال، سفارشی و ... نیز به صورت Type Safety پشتیبانی می‌کند.فکر کنم تنوسته باشید حدس بزنید که با انجام کد مطابق با موارد بالا، همچنان دو مشکل دیگر باقی‌ مانده که نیازه برطرف بشه:در کد بالا، در خط 13 گفتیم که اگر مقدار as پاس داده نشده باشد، مقدار پیش‌فرض آن برابر با button در نظر گرفته شود (از نظر جاوا اسکریپت)، اما مشکلی که وجود دارد این هست که در این صورت اتریبیوت‌های مرتبط با تگ button مانند type، disabled و ... پشتیبانی نمی‌شود. چون جنریک تایپ ما در انتظار انتخاب یک نوع تگ هست و هیچ تگی هم انتخاب نشده است. (از نظر تایپ‌اسکریپت)&lt;Button&gt;click here&lt;/Button&gt;جهت برطرف کردن این مورد ما باید در زمان تعریف کامپوننت مقدار پیش‌فرض جنریک تایپ را هم تعیین کنیم، یعنی آن را برابر با button قرار دهیم: https://gist.github.com/MR-Mostafa/bc593f38eb347e4224c917424bc61109 مورد بعدی اینکه فرض کنید که Polymorphic کامپوننت ما پراپس‌های دیگری مانند color یا font و ... داشته باشد که این پراپرتی‌ها نیز در مقدار پاس داده شده به عنوان as نیز وجود داشته باشد. (یعنی پراپس‌ها با هم تداخل یا همپوشانی داشته باشند) در این صورت برای برطرف کردن این مشکل باید چه کاری انجام دهیم؟فکر کنم این مورد رو در قالب کد توضیح بدم، بهتر باشه. فعلا این کد رو داشته باشید، چون در ادامه می خوام این کد رو اصلاح کنیم و به چند تایپ مستقل تبدیلش کنیم: https://gist.github.com/MR-Mostafa/1ad15ad8045aeaffd9652cf98a736b8b کد بالا رو به صورت زیر ریفکتور کردیم: https://gist.github.com/MR-Mostafa/24655ea37ebbe6c2003d88b8193a5f0d برای رفع عدم تداخل یا هم‌پوشانی پراپرتی های تعیین شده (کاستوم)‌ با پراپرتی های گلوبال یا Third Party کاری که باید انجام بدیم، این هست که از Omit و Keyof در تایپ اسکریپت کمک می‌گیریم، که در نهایت به کد زیر می‌رسیم: https://gist.github.com/MR-Mostafa/8be7ad06481748c7097606c5fd0bdea5#file-polymorphic-components-react-7-tsx-L11 الان می‌تونیم در کامپوننتی که نوشتیم از پراپرتی تعریف شده color استفاده کنیم. در مثال زیر ورودی این پراپرتی رو در اتریبیوت style استفاده می‌کنیم. https://gist.github.com/MR-Mostafa/5e19836e824deadb27d570cc321cb524 الان ما یک کامپوننت چندریختی یا polymorphic داریم که تمام مواردی که گفتیم رو پشتیبانی می‌کنه. برای اینکه بتونیم از این تایپ در موارد گوناگون استفاده کنیم و نیاز نباشه به ازای هر کامپوننت یکبار تمام این مراجل رو پیش بریم، پیشنهاد می کنم که یک تایپ مجزا مثلا به نام PolymorphicWithoutRef در تایپ اسکریپت ایجاد کنید و حالا به ازای هر کامپوننت تنها نیاز هست که این تایپ رو بهش پاس بدید. (طبیعتا این تایپ هم باید جنریک باشد)این بخش آخر رو می‌سپارم به خودتون.فقط یک مورد دیگه باقی موند و اونم بحث ref در مورد کامپوننت ها هست و اینکه چطوری این مقدار رو در کامپوننت های polymorphic به صورت داینامیک مدیریت کنیم، که ان‌شاءالله این مورد رو در قسمت بعدی بهش می‌پردازیم.امیدوارم تا اینجا مفید واقع شده باشد.</description>
                <category>مصطفی رحمتی</category>
                <author>مصطفی رحمتی</author>
                <pubDate>Thu, 23 Nov 2023 00:38:30 +0330</pubDate>
            </item>
                    <item>
                <title>ایجاد کامپوننت‌های چندشکلی در ری‌اکت (Polymorphic Component) - بخش اول</title>
                <link>https://virgool.io/@M.Rahmati/polymorphic-component-in-react-part1-nometkubhpxd</link>
                <description>Polymorphic React Components With TypeScriptقبل از شروع مقاله بهتره سه نکته رو بیان کنم:برای اینکه این آموزش/مقاله حوصله سر بر نشه، احتمالا چندقسمتی خواهد شد و سعی می‌کنم مفاهیم رو تا جایی که در توان و دانشم هست به صورت ساده و روان بیان کنم.مورد بعدی اینکه ساخت این سبک کامپوننت‌ها در جاوااسکریپت مشکل چندانی نداره ولی وقتی نیاز باشه به صورت Type Safety پیاده‌سازی بشه، یکم مباحثش در خصوص تعیین و نحوه تعریف تایپ‌ها دارای پیچدگی می‌شه. سوم اینکه چون مبنای این آموزش بر اساس تایپ‌اسکریپت و ری‌اکت هست پس نیاز هست که شما حداقل با تایپ‌اسکریپت و ری‌اکت آشنا باشید.اصلا Polymorphic Componentها چی هستند؟اگر از UI Liberyهایی نظر MUI، React Bootstrap، Mantine و ... استفاده کرده باشید، حتما با این نوع کامپوننت‌ها مواجه شده‌اید و حتی ممکنه در پروژه‌هاتون ازش استفاده کرده باشید، هرچند ممکنه از نظر مفهومی با اصلاح آن آشنا نباشید.یک کامپوننت Polymorphic در لایبری MUIدر این بخش می خواییم در این مورد صحبت کنیم که:اولاً Polymorphic Componentها چی هستن؟دوماً چه ویژگی‌هایی دارند؟قبل از پاسخ به سوال اول بهتره این رو توضیح بدیم که Polymorphism چی هست. برای پاسخ به این سوال من از مقاله‌ای که در بلاگ فرادرس در این مورد منتشر شده کمک می‌گیرم:باید گفت که پلی مورفیسم (Polymorphism | چندریختی) واژه‌ای یونانی به حساب می‌آید، در لغت به معنی «داشتن چندین شکل و فُرم مختلف» است. در کل اصطلاح Polymorphism یعنی:شرایط رخ دادن و به وقوع پیوستن در فُرم‌های مختلفدر علوم کامپیوتر و برنامه نویسی شی گرا ، شی دارای چند ریختی به شیئی گفته می‌شود که می‌تواند چندین فُرم و شکل را به خود بگیرد.برای اینکه بتوان مشخص کرد که آیا یک شی دارای حالت چندریختی یا به اصطلاح «پلی مورفیک» (Polymorphic) هست یا خیر، می‌توان یک آزمایش ساده انجام داد. در صورتی که آزمون‌های «is-a» (آیا هست؟) یا «instanceof» (نمونه‌ای از) برای آن شی موفقیت‌آمیز باشند، آن شی چندریختی دارد و به اصطلاح «پلی مورفیک» است.به بیان ساده، چندریختی یا پلی مورفیسم (Polymorphism) در برنامه نویسی، استفاده از یک بلوک کد و تغییر «نسخه» آن بلوک کد، بر اساس نوع ورودی‌ها است. اصطلاح پلی مورفیسم یا چندریختی در برنامه نویسی و علوم کامپیوتر به این معنا است که می‌توان به اشیایی با انواع مختلف از طریق رابط و واسطی یکسان دسترسی داشت.حالا با دونستن معنی Polymorphism می‌تونیم حدس بزنیم در لایبری ری‌اکت به چه کامپوننت‌هایی Polymorphic Component می‌گن. در واقع Polymorphic Component به کامپوننت‌هایی گفته می‌شوند که از طریق یک پراپس/ورودی (معمولا به نام &quot;as&quot; یا &quot;component&quot;) می‌توان تعیین کرد که در زمان رندرِ کامپوننت، چه المنتی از المنت‌های HTML در DOM رندر شود.Polymorphic Button Componentیعنی به جای اینکه از چندین کامپوننت جداگانه برای نمایش المنت‌های مختلف استفاده کنیم، یک کامپوننت را با استفاده از پارامترهای متفاوت ورودی، سفارشی‌سازی کنیم. مثلاً فرض کنید یک کامپوننت با نام &quot;Button.tsx&quot; داریم که برای نمایش دکمه‌ها استفاده می‌شود. با استفاده از Polymorphic Component می‌توانیم این کامپوننت را به گونه‌ای پیاده‌سازی کنیم که نوع المنت دکمه به عنوان ورودی قابل تنظیم باشد. (مثلا تگ &quot;a&quot; باشد یا تگ &quot;button&quot; و ...)ویژگی‌ها/ملزومات یک Polymorphic Component:برای اینکه بتونیم بگیم یک کامپوننت، Polymorphic یا چندریختی/چندشکلی هست، حداقل باید دارای چهار ویژگی‌/ملزومات زیر باشد: (پیشنهاد می‌کنم که این ویژگی‌ها رو حتما به‌خاطر بسپارید یا در جایی یادداشت کنید، چون در بخش‌های بعدی هر کدوم از این موارد رو باید پیاده‌سازی کنیم)1. کامپوننت‌مان باید یک پراپس به عنوان ورودی جهت تعیین نوع المنت قبول کند. (در این مقاله ما از نام &quot;as&quot; استفاده می کنیم)2. مقداری که به پراپس &quot;as&quot; پاس می‌دهیم باید در DOM رندر شود. (مثلا تگ span)3. کامپوننت باید موارد زیر نیز پشتیبانی کند:         -  اتریبیوت‌های سراسری/گلوبال مانند id یا class و ...          - از اتریبیوت‌های مختص با المنت تعیین شده، مانند src در تگ img یا href در تگ a و ...         -  پراپس‌های کاستوم/سفارشی در کامپوننت‌های دیگر یا Third Party مثلا کامپوننت Link در فریم‌ورک NextJs پراپس‌هایی مانند replace یا prefetch و ... را دارد.4. در هنگام توسعه به صورت Type Safety پیاده‌سازی شده باشد، در نتیجه؛ تایپ‌اسکریپت در موراد زیر باید خطا نمایش دهد:              - اگر مقدار پاس داده شده به پراپرتی as از نوع المنت‌های معتبر در HTML نباشد. (مثلا المنت test در HTML معتبر نیست و در نتیجه نمی‌توان از آن استفاده کرد)         - اگر از اتریبیوتِ اشتباهی که مختص به آن المنت نیست، استفاده شود. مثلا تگ img اتریبیوت href را ندارد.         - اگر مقدار ref اشتباهی به کامپوننت پاس داده شود. (در مورد کامپوننت‌هایی که قابلیت forwardRef را دارند.) مثلا کامپوننت ما یک button است ولی مقدار ref به یک المنتی غیر از button اشاره می‌کند.بنظرم برای بخش اول تا همین‌جا کافی هست. مابقی موارد رو در بخش‌های دیگه سعی می‌کنم توضیح بدم. اگر مورد خاصی برای بخش اول بهتر هست گفته بشه که از قلم افتاده یا اشتباهی در نگارش وجود داره ممنون می‌شم از طریق نظرات بهم اطلاع بدید تا ویرایش لازم رو انجام بدم.ضمنا منابعی که من برای نوشتن این مجموعه مقالات استفاده کردم فعلا موارد زیر هست:https://b.fdrs.ir/58jhttps://blog.logrocket.com/build-strongly-typed-polymorphic-components-react-typescript/https://isamatov.com/polymorphic-components-react-typescript/https://betterprogramming.pub/react-polymorphic-components-with-typescript-real-practice-example-94c8a205d079https://jarocki.me/notes/polymorphic-react-componentshttps://www.udemy.com/course/build-polymorphic-components-with-react-and-typescript/</description>
                <category>مصطفی رحمتی</category>
                <author>مصطفی رحمتی</author>
                <pubDate>Mon, 23 Oct 2023 09:58:45 +0330</pubDate>
            </item>
                    <item>
                <title>افزایش عرض tooltip و دردسرهای آن</title>
                <link>https://virgool.io/@M.Rahmati/%D8%A7%D9%81%D8%B2%D8%A7%DB%8C%D8%B4-%D8%B9%D8%B1%D8%B6-tooltip-%D9%88-%D8%AF%D8%B1%D8%AF%D8%B3%D8%B1%D9%87%D8%A7%DB%8C-%D8%A2%D9%86-wkfazarg1kig</link>
                <description>چند وقتی هست که مشغول مطالعه کتاب javascript and jquery interactive front-end web development هستم. تا اینجا که هم چی عالی بوده و واقعا این کتاب به نظرم برای یادگیری جاوااسکریپت محشره. بعد از خوندن چند فصل از کتاب، تصمیم گرفتم یه Form Validation درست کنم (پروژه‌ی عملی / در حد مبتدی و سطح خودم)؛ بنابراین از دیروز شروع کردم مقدمات کار رو انجام دادن. (کارهای HTML و CSS)تا اینجای کار اینو درست کردمبه ذهنم رسید که یه tooltip هم برای نمایش یکسری اطلاعات، قرار بدم که به کاربر یکسری توضیحات رو نمایش بده. (با رفتن موس بر روی علامت سوال). خوب طبیعتاً برای جای‌گذاریش در صفحه ناچار هستیم از خاصیت Position در CSS استفاده کنیم، که اینکار رو هم انجام دادم و این شد ماحصل کار:مشکلی که الان وجود داره، اینه که اگه متن tooltip افزایش یا کاهش پیدا کنه، باید مجدد جای‌گذاری tooltip محاسبه و تنظیم بشه. (خاصیت left)این کدها: (چون ویرگول کدها رو اشتباه نمایش می‌داد، عکس گذاشتم)و اینم خروجی و مشکل ایجاد شده:نتیجه  راهکارهایی که به ذهنم رسید این بود: 1) به tooltip یه عرض ثابت و همیشگی بدم، که زیاد جالب‌ناک نمی‌شه. چون بعضی مواقع لازم هست که عرض tooltip کم باشه، که طبیعتاً زیبایی کار رو خراب می‌کنه.2) راه حل دوم استفاده از جاوااسکریپت هست. به این صورت که عرض tooltip رو با جاوااسکریپت بگیرم و پوزیشن‌ها رو بر اساس عرض به‌دست‌آمده مجدد محاسبه و تنظیم کنم. چون کلا راه‌کارها و حقّه‌های CSS برام جذاب هست، نتیجتاً این کار رو هم نکردم.3) راه حل سوم استفاده از کتاب‌خونه‌های مختلف هست که tooltip رو خیلی شیک و مجلسی پیاده سازی کردن و البته اون هم به طور معمول با استفاده از جاوااسکریپت هستش.4) راه حل چهارمی که به نظرم رسید و می‌خوام پیاده‌سازیش کنم، استفاده از یک div نگه‌دارنده هست که به این صورت تمام tooltip در یک div نگه‌دارنده قرار می‌گیره که غیر از خاصیت Position هیچ خاصیت CSS دیگه مثل بک‌گراند نداشته باشه. همچنین برای اون div یک عرض حداکثری تعیین کنم تا بیشتر از اون نشه ( یعنی max-width) و به اولین فرزندش خاصیت display: inline-block رو تعیین کنم تا تمام عرض والد خودش رو در حالت پیش‌فرض نگیره و به مقدار مورد نیاز فضا اِشغال کنه.بیایید این روش رو باهم پیاده سازی کنیم، خوب کدهام رو دیدید، با یک تغییرات جزئی کدها به صورت زیر تبدیل می‌کنم:اینم خروجی:این هم لینک کدها:https://codepen.io/MR-Mostafa/pen/oOLONR در پایان این رو هم یادآوری کنم که قطعا روش‌های دیگه‌ای هم برای اینکار وجود داره که نیاز به کمکی تمرکز و فکر کردن داره.این فقط بخش شروع هست و قطعا برای ادامه‌ی ماجرا نیاز به جاوااسکریپت هست که اونو هنوز انجام ندادم.متوجه نشدم چرا ویرگول کدها رو جدا کرد و خراب نشون می‌ده؟! @virgoolبه همین خاطر، کدها رو به صورت عکس قرار دادم.</description>
                <category>مصطفی رحمتی</category>
                <author>مصطفی رحمتی</author>
                <pubDate>Sat, 06 Apr 2019 23:48:56 +0430</pubDate>
            </item>
            </channel>
</rss>