<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های علی مقیمی</title>
        <link>https://virgool.io/feed/@m_88441671</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-04-15 08:55:58</pubDate>
        <image>
            <url>https://static.virgool.io/images/default-avatar.jpg</url>
            <title>علی مقیمی</title>
            <link>https://virgool.io/@m_88441671</link>
        </image>

                    <item>
                <title>تکنیک های بهینه سازی context برای افزایش performance در React</title>
                <link>https://virgool.io/@m_88441671/%D8%AA%DA%A9%D9%86%DB%8C%DA%A9-%D9%87%D8%A7%DB%8C-%D8%A8%D9%87%DB%8C%D9%86%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-context-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%A7%D9%81%D8%B2%D8%A7%DB%8C%D8%B4-performance-%D8%AF%D8%B1-react-btrxduwz9rn7</link>
                <description>ابزار Context توی React ابزار قدرتمندیه، ولی اگر بدون دقت استفاده بشه می‌تونه به یکی از بزرگ‌ترین دلایل افت Performance تبدیل بشه. مخصوصاً وقتی stateهایی داریم که زیاد تغییر می‌کنن (مثلاً هر ثانیه). توی این مطلب، مهم‌ترین نکات عملی برای بهینه‌سازی Context رو به‌صورت مرحله‌به‌مرحله مرور می‌کنیم.هر تغییری در Context به معنای re-render شدن همه مصرف‌کننده‌هامهم‌ترین نکته‌ای که خیلی وقت ها ممکنه نادیده گرفته میشه اینه که:با هر تغییر value در Context، تمام کامپوننت‌هایی که از اون Context استفاده می‌کنن re-render می‌شن.حتی اگر اون کامپوننت، اون state ای که تغییر کرده را استفاده نکرده باشه و بهش مربوط نباشه. بصورت کلی اگر کامپوننتی هوک useContext رو در خودش فراخوانی کنه، با تغییر هر state درون context، دوباره رندر میشه که این رندر غیرضروری و اضافی هست و باعث کاهش کارایی برنامه میشه.با توجه به این مساله، Context اصلاً برای stateهایی که زیاد و با فرکانس بالا تغییر می‌کنن (مثل time، scroll، mouse position) گزینه‌ی خوبی نیست.ولی با این روش هایی که تو ادامه بررسی می کنیم میشه این re-render های اضافی و غیرضروری رو حذف کرد.1️⃣ جداسازی State ها و Actionها در Context:منظور از Action ها همون توابع setState ای هستن که تو کانتکست وجود دارن. اما هدف از این جداسازی، اینه که:کامپوننت‌هایی که فقط از این action ها استفاده کردن (و state ای رو set کردن)، با تغییر state دوباره render نمی‌شن.درخت رندرها خیلی کوچیک‌تر می‌شه(یعنی کامپوننت هایی که دوباره رندر میشن، کمتر میشن)نحوه پیاده سازی به این شکله:StateContext  -&gt; data
ActionsContext -&gt; setData, updateSomethingیک Context برای stateیک Context جدا برای actions / setters&lt;StateContext.Provider value={states}&gt;
   &lt;ActionsContext.Provider value={actions}&gt;
     {children}
   &lt;/ActionsContext.Provider&gt;
&lt;/StateContext.Provider&gt;2️⃣ قراردادن value مربوط به Provider در useMemo داخل کانتکست:وقتی کانتکست رو این شکلی می نویسیم:&lt;MyContext.Provider value={{ state, setState }}&gt;در هر render، یک آبجکت جدید ساخته می‌شه ❌و React فکر می‌کنه Context تغییر کرده. درحالیکه مقادیر داخل value ممکنه تغییری نداشته باشن. در نتیجه یه re-render اضافی برای تمام کامپوننت های تحت پوشش خودش اعمال می کنه.پس باید اون رو داخل useMemo قرار بدیم:const value = useMemo(

  () =&gt; ({ state, setState }),

  [state]

);3️⃣ جداسازی و بیرون آوردن state های پرنوسان:Stateهایی مثل:time (هر ۱ ثانیه)websocket dataanimation progress❌ نباید داخل Context باشن. چون هربار که با فرکانس بالا تغییر می کنن؛ re-render های زیادی رو به اپ تحمیل می کنن. (کلا کانتکست برای چنین متغیرهایی طراحی نشده.)راه‌حل بهتر:useSyncExternalStorelocal stateیا حتی event-based patternقراردادن در ref4️⃣ جداسازی Context (سراسری) طبق مسئولیت یا feature-based:با توجه به مساله ی re-rendering کانتکست که بالاتر بررسی کردیم؛ بهتره کانتکست ها رو بر مبنای ویژگی(feature-based) از هم جدا کنیم(یا بر هر مبنای دیگه ای که مناسب دیدیم).این کار باعث میشه کامپوننت هایی که با بعضی state ها تو کانتکست ارتباطی ندارن؛ با تغییر این state ها بطور بیهوده re-render نشن و اینطوری  re-render اضافی حذف میشه.UserContextThemeContextAuthContext5️⃣ استفاده از context selector:یه پکیجی به نام use-context-selector هست که امکان انتخاب بخش مشخصی از Context را فراهم می‌کنه.در این حالت، کامپوننت فقط زمانی re-render می‌شه که همان state یا مقداری که انتخاب کرده تغییر کنه، نه با هر تغییر در کل Context.به این ترتیب، مشکل re-renderهای اضافی که معمولاً هنگام استفاده‌ی مستقیم از useContext به‌وجود میاد، تا حد زیادی برطرف می‌شه.مثال استفاده از use-context-selector6️⃣ استفاده از External store:تو React یه هوک خیلی خفن داریم به اسم useSyncExternalStore که عملاً میاد یه store  برامون درست می‌کنه (یه چیزی شبیه Redux، ولی خیلی سبک‌تر).با این هوک می‌تونیم stateهامون رو بین چند تا کامپوننت به اشتراک بذاریم، بدون اینکه مجبور باشیم Provider درست کنیم یا کل درخت کامپوننت ها رو بهش وصل کنیم.نکته‌ی جذابش اینه که performance خیلی بالایی داره؛ چون هر کامپوننت فقط به همون بخشی از store که بهش subscribe کرده گوش می‌ده و فقط وقتی همون مقدار عوض بشه re-render می‌شه.نه اینکه با هر تغییر کوچیک، نصف اپ دوباره رندر بشه 😅این یعنی:کامپوننت‌های بینابینی اصلاً درگیر نمی‌شنre-renderهای اضافی حذف می‌شندرخت render کوچیک‌تر و تمیزتر می‌شه (در واقع هرس می‌شه)من خودم تو پروژه‌هایی که state پرنوسان داشتن تجربه‌ی خیلی خوبی باهاش داشتم و بهبود performance کاملاً محسوس بود.7️⃣ قرار دادن consumer ها در memo:این راه هم می تونه مکمل باشه و جلوی re-render های عمیق رو بخاطر تغییر props ها بگیره. اما باید با دقت استفاده بشه که موثر واقع بشه.جمع‌بندیکانتکست ابزار خیلی خوب و قدرتمندیه، ولی اگه بدون دقت و برای هر چیزی ازش استفاده کنیم، خیلی راحت می‌تونه تبدیل بشه به گلوگاه performance اپلیکیشن.اگه stateهایی داریم که:زیاد تغییر می‌کننبه همه‌ی کامپوننت‌ها ربطی ندارنیا باعث re-renderهای زنجیره‌ای شدنمی تونیم با استفاده از راه هایی که بررسی کردیم؛ performance اپلیکیشن رو بهبود بدیم.خیلی ممنون که تا اینجا همراه بودین.اگر دوست داشتین برام تو کامنتا بنویسین که شما از چه راه هایی برای بهینه سازی کانتکست استفاده می کنین.با آرزوی سلامتی و موفقیت برای همه ی شما عزیزان.</description>
                <category>علی مقیمی</category>
                <author>علی مقیمی</author>
                <pubDate>Sat, 31 Jan 2026 14:16:01 +0330</pubDate>
            </item>
                    <item>
                <title>بهینه سازی کدهای جاوااسکریپت با تب performance کروم</title>
                <link>https://virgool.io/@m_88441671/%D8%A8%D9%87%DB%8C%D9%86%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%DA%A9%D8%AF%D9%87%D8%A7%DB%8C-%D8%AC%D8%A7%D9%88%D8%A7%D8%A7%D8%B3%DA%A9%D8%B1%DB%8C%D9%BE%D8%AA-%D8%A8%D8%A7-%D8%AA%D8%A8-performance-%DA%A9%D8%B1%D9%88%D9%85-xtxldq4y9i7a</link>
                <description>چطوری کدهای js پروژه مون رو با استفاده از تب performance مرورگر کروم بهینه سازی کنیم؟سلام.مرورگر یه نخ(thread) داره که تمام کار(task)های لازم برای نمایش صفحه رو توش انجام میده. این نخ، نخ اصلی یا main thread نام داره. کارهایی مثل اجرای کدهای جاوااسکریپت ، رندرینگ، تجزیه ی html , css و کارهایی که شاید ما روی اون ها کنترلی نداشته باشیم. . اگر این نخ (توسط یک تسک) مسدود بشه؛ یعنی یه تسک مقدار زمان زیادی برای اجرا به خودش اختصاص بده(حداقل 50 میلی ثانیه)؛ توی این نخ، مرورگر تسک های مهم و بحرانی رو نمی تونه انجام بده. در نتیجه این موضوع باعث میشه که :- سرعت load پایین بیاد.- واکنش گرایی صفحه نسبت به اکشن ها و درخواست های کاربر پایین بیاد(یعنی کندی در اجرا) (unresponsive بودن).- تجربه ی کاربری هم بد بشه.مهم ترین عوامل مسدود شدن نخ اصلی در مرورگر، تسک های بزرگ یا Long Task ها هستن که معمولا کدهای جاوااسکریپت ما هستن.برای حل این مساله، ما باید long task ها رو شناسایی کنیم و بعد اون ها رو به تسک های کوچکتر جاوااسکریپتی بشکنیم و خرد کنیم.شناسایی و یافتن long task ها:برای یافتن long task ها، از تب performance مرورگر میشه استفاده کرد. به این صورت که اول دکمه ی رکوردش رو می زنیم و بعد صفحه رو رفرش می کنیم. بعد قسمت Main اش رو باز می کنیم. می بینیم که یکسری نوار با هاشور قرمز وجود داره که نمایانگر تسک های طولانی هستن. یه نمونه تو تصویر زیر داریم که مربوط به سایت دیجیکالا هست.شکستن تسک های طولانی:شکستن تسک های طولانی به تسک های کوچکتر، باعث میشه که مرورگر فرصتی بیشتری برای پاسخ به کارهای با اولویت بالاتر (یعنی تعامل با کاربر و بروزرسانی سریعتر UI) داشته باشه. پس این کار مهمه. برای شکستن تسک های طولانی، سه تا استراتژی وجود داره:1) به تعویق انداختن دستی کدها2) استفاده از async/await برای ایجاد نقاط yield.3) استفاده از yield تنها وقتی که نیاز است.در ادامه، توضیح هرکدوم از روش ها رو باهم بررسی می کنیم:1) تو این استراتژی، از تابع setTimeout جاوااسکریپت استفاده میشه که توابع و کدهایی که درون callback این تابع قرار میگیرن، به تسک های جداگانه و مجزا تبدیل میشن و به تعویق می افتن. مثالش رو میشه تو کد زیر باهم ببینیم. تو این کد، می خوایم تسک طولانی saveSettings رو به تسک های کوچکتر خرد کنیم. برای اینکار، توابع saveToDatabase , saveAnalytics (که برای کاربر قابل مشاهده نیستن) با استفاده از setTimeout ،به تسک های جداگانه ای نسبت یه سایر توابع تبدیل میشن و از این تسک طولانی جدا میشن. این استراتژی برای مواقعیه که ما یکسری تابع داریم که پشت سرهم اجرا میشن.function saveSettings () {
 // Do critical work that is user-visible:
 validateForm();
 showSpinner();
 updateUI();

 // Defer work that isn&#039;t user-visible to a separate task:
 setTimeout(() =&gt; {
 saveToDatabase();
 sendAnalytics();
 }, 0);
}2) معنی yield کردن یعنی ایجاد وقفه در انجام یک تسک(برای ایجاد تسک با اولویت بیشتر). مثلا وقتی تسکی وجود داره که درحال بروزرسانی UI برای کاربر هست. تسک فعلی باید به وقفه بیافته(yield بشه). وقفه انداختن یک تسک، باعث میشه که مرورگر که تسک ها رو با مکانیزم درونی خودش اولویت بندی میکنه، تسک های با اولویت بالاتر زودتر انجام بده. تو این استراتژی، بعد از هر تسک(تابع) یک وقفه ایجاد میشه(مانند مثال پایین) برای ایجاد yield، از Promise, setTimeout استفاده میشه که مثالش رو تو کد زیر می تونیم ببینیم. کد زیر، همون تسک طولانی saveSettings رو با استفاده از این استراتژی به تسک های کوچکتر تبدیل کرده. ابتدا یه تابع yieldToMain نوشته که هر کجا از کد لازم بود با استفاده از این تابع تو تسک درحال اجرای فعلی وقفه ایجاد کنه:function yieldToMain () {
 return new Promise(resolve =&gt; {
 setTimeout(resolve, 0);
 });
}بعد تسک طولانی saveSettings رو که از چندین تابع تشکیل شده، به تسک های کوچکتر تبدیل میکنه. یعنی بعد از هر تسک، یه وقفه(yield) داخل نخ اصلی ایجاد می کنه.3) اما اگر بخوایم برعکس استراتژی بالا، هرجا نیاز بود در اجرای تسک طولانی فعلی وقفه ایجاد کنیم و به این شکل تسک طولانی رو خرد کنیم چطور؟ مثلا وقتی کاربر توی صفحه اکشنی انجام میده، توی تسک طولانی فعلی که درحال اجراست وقفه ایجاد کنیم، بعد تسک های مربوط به انجام کارهای کاربر رو انجام بدیم(مثلا بروزرسانی ui)، سپس به انجام تسک های پس زمینه ادامه بدیم چی؟؟ این استراتژی باعث میشه که کاربر هیچگونه کندی ای مشاهده نکنه و ما فقط هرجا که لازمه وقفه تو اجرای Long task ایجاد کنیم نه همه جا(ممکنه در هرجایی، ایجاد وقفه درون تسک طولانی لازم نباشه). برای این کار از یک تابع به اسم isInputPending که تو شی scheduler در شی navigator مرورگر قرار داره استفاده میشه. وقتی کاربر با صفحه تعاملی انجام میده، این تابع true بر می گردونه. نحوه ی استفاده اش هم تو مثال پایین اومده:async function saveSettings () {
 // A task queue of functions
 const tasks = [
    validateForm,
    showSpinner,
    saveToDatabase,
    updateUI,
    sendAnalytics
 ];
 
 while (tasks.length &gt; 0) {
 // Yield to a pending user input:
 if (navigator.scheduling.isInputPending()) {
 // There&#039;s a pending user input. Yield here:
 await yieldToMain();
 } else {
 // Shift the task out of the queue:
 const task = tasks.shift();

 // Run the task:
 task();
 }
 }
}ما می خوایم یه long task به اسم saveSettings رو به تسک های کوچکتر بشکنیم. اول چک می کنیم که کاربر با صفحه تعامل داره یا نه؟ اگر داشت با استفاده از تابع yieldToMain (که تو مثال قبل نوشتیم)، وقفه رو ایجاد می کنیم. اما اگر تعاملی وجود نداشت، تسک کوچک شده ی فعلی رو اجرا می کنیم.استفاده از زمانبند اختصاصی مرورگر(scheduler):تمام کارهایی که ما در قسمت های بالا انجام دادیم، پیاده سازی بصورت دستی هستن. اما مرورگر خودش یک scheduler داره که به ما این امکان رو میده که کارهای بالا رو بصورت خودکار انجام بدیم. این api مرورگر، یه تابع به اسم postTask داره به سه اولویت:اولویت &quot;background&quot; برای وظایف با کمترین اولویت.اولویت &quot;user-visible&quot; برای وظایف با اولویت متوسط. اگر اولویتی تنظیم نشده باشد، این پیش‌فرض است.اولویت &quot;user-blocking&quot; برای کارهای حیاتی که باید با اولویت بالا اجرا شوند.مثالش رو هم در ادامه می تونیم ببینیم:function saveSettings () {
 // Validate the form at high priority
  scheduler.postTask(validateForm, {priority: &#039;user-blocking&#039;});

 // Show the spinner at high priority:
  scheduler.postTask(showSpinner, {priority: &#039;user-blocking&#039;});

 // Update the database in the background:
  scheduler.postTask(saveToDatabase, {priority: &#039;background&#039;});

 // Update the user interface at high priority:
  scheduler.postTask(updateUI, {priority: &#039;user-blocking&#039;});

 // Send analytics data in the background:
  scheduler.postTask(sendAnalytics, {priority: &#039;background&#039;});
};
منبع:https://web.dev/optimize-long-tasks/?utm_source=devtools</description>
                <category>علی مقیمی</category>
                <author>علی مقیمی</author>
                <pubDate>Thu, 17 Aug 2023 22:52:07 +0330</pubDate>
            </item>
                    <item>
                <title>بهینه کردن کارایی(performance) فیلتر و مرتب کردن لیست ها با کتابخانه ی Reselect و Re-reselect در ریداکس</title>
                <link>https://virgool.io/@m_88441671/%D8%A8%D9%87%DB%8C%D9%86%D9%87-%DA%A9%D8%B1%D8%AF%D9%86-%DA%A9%D8%A7%D8%B1%D8%A7%DB%8C%DB%8Cperformance-%D9%81%DB%8C%D9%84%D8%AA%D8%B1-%D9%88-%D9%85%D8%B1%D8%AA%D8%A8-%DA%A9%D8%B1%D8%AF%D9%86-%D9%84%DB%8C%D8%B3%D8%AA-%D9%87%D8%A7-%D8%A8%D8%A7-%DA%A9%D8%AA%D8%A7%D8%A8%D8%AE%D8%A7%D9%86%D9%87-%DB%8C-reselect-%D9%88-re-reselect-%D8%AF%D8%B1-%D8%B1%DB%8C%D8%AF%D8%A7%DA%A9%D8%B3-w47wkleivb4z</link>
                <description>سلام.تو این مطلب می خوایم باهم بررسی کنیم که راه درست فیلتر کردن یا مرتب کردن یک لیست (که حجم بسیار بالایی هم داره) در react app چیه و اون رو نسبت یه راه عادی که به ذهنمون میرسه مقایسه کنیم.اگر در یک react app که در اون از redux استفاده شده، بخوایم حجم زیادی از داده رو فیلتر (یا sort ) کنیم، یقینا اولین راهی که به ذهن هممون می رسه اینه که این کار رو داخل reducer در ریداکس انجام بدیم.اما راه درست انجام این کار اینه که اصل داده ها رو داخل یه state درون store نگه داریم و  فیلتر یا مرتب کردن داده ها رو داخل selector ها انجام بدیم.(نه داخل reducer ها)فواید استفاده از این روش به شرح زیره:1)نیازی به ذخیره ی موارد فیلتر شده در state کلی درون store نیست.(چون محاسبه می شه و در اختیار کامپوننت مربوطه قرار می گیره)2) اگر چند کامپوننت بخوان با معیارهای مختلفی داده ی اصلی رو فیلتر کنن، این امکان فراهمه.3) امکان ترکیب selector ها (فیلتر کننده ها) وجود داره؛ یعنی ما می تونیم تو چند مرحله فیلترکردن رو انجام بدیم.4) سلکتورها، pure function میشن ، پس تست کردنشون راحت تره.5) امکان استفاده ی دوباره ای selector ها در کامپوننت های مختلف وجود داره(reusable شدن selector ها).6) وقتی عملیات فیلتر یا مرتب کردن بسیار سنگین و هزینه بر باشه، این روش بسیار کارآمدتر هست.7) داده (state ) اصلی درون store، راحت تر خوانده میشه.(خوانایی بالاتر)8) برای محاسبه ی مقادیر فیلتر یا sort، منطق کمتری نیاز هست.9) داده اصلی(root state) دست نخورده باقی می مونه.اما فیلتر کردن یا مرتب کردن (یا هر عملیات دیگری به این شکل) داده ها در selector ها، دو نگرانی ایجاد می کنه:1) با هر بار dispatch شدن یک action در redux ، سلکتور(Selector) استفاده شده درون useSelector یا mapState دوباره اجرا میشن(re-run)، فارغ از اینکه چه قسمتی از state کلی درون store تغییر کرده و بروز شده(یعنی اون قسمت به این selector ارتباط داشته یا نه). (با استناد به documentation ریداکس). اجرای دوباره(re-run) شدن این محاسبات سنگین آن هم با عدم تغییر آن قسمت از state کلی ورودی به کامپوننت مربوطه، بیهوده هست و بار زمانی و پردازشی اضافی بر روی cpu داره.2) توابع useSelector و mapState، با استفاده از عملگر &quot;===&quot; ، چک می کنند که آیا خروجی selector موردنظر بعد از اجرا، تغییر کرده یا نه؟ اگر تغییر کرده باشه( یعنی بازگردانی رفرنس جدید)، کامپوننت مربوطه رو مجبور به re-render می کنند. حتی اگر مقادیر داده ی درون این شی یا آرایه تغییری نکرده باشه(و این بازهم به معنی پردازش بی مورد و اضافه هست). این عملیات معمولا در سلکتورهایی رخ میده که در اونا از تابع map یا filter جاوااسکریپت استفاده میشه. چون این توابع هربار یه رفرنس جدید بر می گردونن.برای حل نگرانی ها و مشکلات بالا، سلکتورها رو memoize می کنن. یعنی مجموعه ی ورودی ها و خروجیشون رو ذخیره می کنن؛ اگر ورودی ها تغییر کنه، سلکتور دوباره اجرا میشه و بعد دوباره این مجموعه ی ورودی و خروجی ذخیره میشه. اگر مجموعه ی ورودی تغییر نکنه، سلکتور دوباره اجرا نمیشه و همون خروجی کش(cache) شده بازگردانی میشه. اینطوری بار پردازشی اضافه حذف میشه.برای نوشتن سلکتورهای memoize شده، از کتابخونه ای به اسم Reselect استفاده میشه که این کتابخونه با ریداکس بطور خودکار نصب میشه.کتابخونه ی Reselect ، یک تابع به اسم createSelector داره که مجموعه سلکتورهای ورودی و یک سلکتور خروجی رو می گیره، بعد مقدار فیلتر یا مرتب شده رو بر می گردونه. یعنی داده های اولیه ی درون state رو می گیره، تو سلکتور خروجی فیلتر رو انجام میده و مقدار رو بر می گردونه.نوشتن memoized selector با استفاده از createSelectorمثلا در کد بالا، سلکتور selectABC با استفاده از createSelector ایجاد میشه که 4 تا ورودی می گیره. سه تای اول(selectA, selectB, selectC) سلکتورهایی هستن که داده های ورودی selectABC رو از state کلی انتخاب(select) می کنن و به selectABC میدن. ورودی آخری هم سلکتور خروجی هست، که مقادیر خروجی سلکتورهای اول(یعنی selectA, selectB, selectC) درون ورودی این سلکتور قرار می گیره؛ بعد ما می تونیم عملیات مدنظرمون رو روی این داده ها انجام بدیم. مثلا عملیات فیلترکردن یا مرتب سازی یا... . بعد مقدار نهایی رو return می کنه.نحوه ی کارکرد تابع createSelector:وقتی این تابع فراخونی میشه، کتابخونه ی reselect، سلکتورهای ورودی(selectA, selectB, selectC در مثال بالا) داده شده رو اجرا می کنه، بعد مقدار خروجی هرکدوم از اونها رو (با استفاده از عملگر ===)بررسی می کنه، اگر حتی یکی از خروجی های بررسی شده، رفرنس جدیدی نسبت به قبل باشن(برای اشیا و آرایه ها)، کتابخانه ی reselect ، سلکتور خروجی(مثلا آخرین تابع ورودی در مثال بالا) رو دوباره اجرا می کنه و مجموعه ی ورودی های سلکتور خروجی به همراه مقدار return شده (نتیجه) ی اون رو کش(cache) می کنه. اما اگر هیچ کدوم از رفرنس های سلکتورهای ورودی تغییر نکرده باشن، همون آخرین مقدار نتیجه کش شده را بازگردانی می کنه.مشکل کتابخانه ی reselect و تابع createSelector:اما مشکلی که تابع createSelector داره اینه که فقط می تونه یک مقدار رو برای هر عملیات ذخیره کنه(فقط یک ظرفیت حافظه بهش اختصاص داده شده). مشکل تابع createSelector مثلا تو مثال بالا، وقتی سلکتور memoize شده با مقدار 1 فراخوانی میشه، مقدار خروجی برای ورودی 1 ذخیره میشه، بعد که دوباره با 1 فراخونی میشه، سلکتور خروجی دوباره اجرا نمیشه و آخرین مقدار ذخیره شده تو حافظه اختصاص داده شده به این تابع بازگردانی میشه. در ادامه وقتی با مقدار ورودی 2 فراخوانی میشه، سلکتور خروجی اجرا میشه و خروجی جدید رو ایجاد می کنه و نتیجه (جایگزین مقدار خروجی آرگومان 1 میشه و) کش میشه. اما در انتها، وقتی دوباره این تابع با مقدار 1 (بعد از فراخوانی اون با مقدار 2) فراخوانی میشه، سلکتور خروجی دوباره اجرا میشه(چون در تنها ظرفیت حافظه ی این تابع خروجی آرگومان 2 وجود داره) و مقدار رو برای ورودی 1 (دوباره) محاسبه می کنه و جایگزین مقدار خروجی آرگومان 2(که قبلا ذخیره شده بود) میشه.  در واقع سلکتور ایجاد شده با تابع createSelector ، چون فقط 1 ظرفیت حافظه برای ذخیره و کش کردن مقدار نتیجه ی سلکتور خروجی داره، هربار مقایسه رو نسبت به نتیجه ی عملیات ورودی قبلی خودش انجام میده. دیگه کاری به خروجی های قبل تر نداره. چون مقدار حافظه اش اجازه نمی ده و  خروجی های آرگومان های قبلی رو نداره که مقایسه کنه.حل مشکل reselect با استفاده از re-reselect :re-reselectبرای حل این مشکل، از کتابخونه ی دیگه ای به نام Re-Reselect استفاده می کنیم. این کتابخونه، یک کتابخونه ی wrapper برای reselect هست که میاد چندین سلکتور ایجاد شده از تابع createSelector رو کش می کنه؛ برای هر سلکتور کش شده هم یک کلید(key) در نظر می گیره که همون آرگومان ورودیش هست. بعد طبق ورودی(یا همون key) که موقع فراخونی می گیره، تصمیم می گیره که یک سلکتور memoize شده ی جدید با createSelector ایجاد کنه و کلید و خروجی این سلکتور جدید رو کش کنه و بازگردانی کنه، یا بره سراغ سلکتورهای کش شده ی قبلی و خروجیشون رو به ما بده.تو تصویر بالا، می تونیم ببینیم که شکل سمت چپ، یک سلکتور ایجاد شده با reselect هست و شکل سمت راست، مجموعه ای از سلکتورهای کش شده که با توجه به ورودی تابع ایجاد شده با re-reselect ، تصمیم گیری میشه که اگر این کلید وجود داشت، خروجی متناظرش بازگردانی شه، اگر هم وجود نداشت، یک سلکتور براش ایجاد شه و فراخونی شه و مقدارش کش و سپس بازگردانی شه.در ادامه یک نمونه کد از این کتابخونه رو می تونیم بررسی کنیم:مثال re-reselectتو کد بالا، یک سلکتور cache شده به نام getUsersByLibrary  با تابع createCachedSelector که مخصوص کتابخونه ی re-reselect هست( مثل زمانیکه با createSelector ایجاد می کردیم)، ایجاد شده با این تفاوت که یک کلید به نام libraryName هم تو ورودیش دریافت می کنه. هنگام فراخوانی getUersByLibrary ، یک کلید هم بهش داده میشه(مثلا در اینجا &#x27;react&#x27; یا &#x27;vue&#x27;). اگر به ترتیب فراخوانی ها دقت کنیم، می بینیم که اول سلکتور getUsersByLibrary با ورودی (یا همون کلید) &#x27;react&#x27; فراخوانی شده و نتیجه اش ذخیره شده. بعد با ورودی &#x27;vue&#x27; فراخوانی شده، بعد با همون &#x27;react&#x27;. اما در فراخوانی آخر با ورودی(کلید) &#x27;react&#x27; ، دیگه سلکتور جدیدی برای این کلید ایجاد نمیشه و سلکتور خروجی expensiveComputation دوباره (و بیهوده) اجرا نمیشه و به cache مراجعه میشه و مقدار ذخیره شده برای کلید(ورودی) &#x27;react&#x27; به ما داده میشه.به این شکل، با استفاده از memoization و سلکتورها، عملیات فیلترکردن و مرتب سازی در سلکتورها انجام میشه و کارایی بهتری رو خواهیم داشت.این نتیجه ی تحقیقی بود که بنده انجام دادم. اگر اشکال و یا ایرادی و کمی و کاستی ای در این مطلب موجود هست، خوشحال میشم که تو کامنت ها بگین. با تشکر که تا به اینجا همراهی کردین.با آرزوی موفقیت و سلامتی.منابع:https://stackoverflow.com/questions/34003553/redux-what-is-the-correct-way-to-filter-a-data-array-in-reducerhttps://redux.js.org/usage/deriving-data-selectorshttps://blog.logrocket.com/react-re-reselect-better-memoization-cache-management/https://github.com/toomuchdesign/re-reselect</description>
                <category>علی مقیمی</category>
                <author>علی مقیمی</author>
                <pubDate>Fri, 06 Jan 2023 17:31:40 +0330</pubDate>
            </item>
                    <item>
                <title>react-admin چیست؟</title>
                <link>https://virgool.io/@m_88441671/react-admin-%DA%86%DB%8C%D8%B3%D8%AA-sfm7mozdhc12</link>
                <description>بسم الله الرحمن الرحیم.بعد از کلی سرچ کردن و بالا-پایین کردن گزینه های مختلف برای پیداکردن یه قالب واسه پیاده سازی پنل کاربری(داشبورد) وبسایتی که با کتابخونه ی reactjs نوشته میشه، به قالبی رسیدیم که واقعا از هرنظر نسبت به بقیه بهتر بود و کارکردن باهاش خیلی راحته. همچنین، از نظر سرعت و کارایی هم سریع و خوبه و خیال آدم رو یه جورایی راحت می کنه. ازنظر داکیومنت هم واقعا نسبت به بقیه ی قالب ها بسیار بهتر کارکرده. تعداد ستاره ها و fork ها در گیت هاب و دانلود هفتگی در npmjs اش هم نسبت به بقیه ی قالب های از این دست بسیار بیشتر و تفاوت چشمگیری داره.تصویری از پنلی که با این ابزار ایجاد میشه اسم این قالب  react-admin  هست که آدرس داکیومنتش تو این لینکه. خود شرکتی که این قالب رو پیاده  سازی کرده، یه دمو براش ایجاد کرده که آدرس اون هم اینجاست. بنابراین میشه کارایی که با این تمپلیت قابل انجام هست رو بفهمیم و ایده و الگو بگیریم. همچنین، یه کار خیییلیییی خوبی هم که این شرکت انجام داده، قراردادن سورس کد این دمو رو هم برای ماست که واقعا  استفاده ازش برای من بسیار مفید بود و تونستم چیزای جدیدی هم با نگاه کردن به همین کدها و نحوه ی پیاده سازی قسمت های مختلف این دمو یادبگیرم و بعضا تو انجام کارایی که می خواستم انجام بدم کارگشا بود.خوب حالا ویژگی های این ابزار چیه؟ تو ادامه یه نگاهی بهشون می اندازیم:برخی ویژگی های react-admin :سازگاری با هر نوع بک اند( rest api , graphql , soap ,... ).پشتیبانی و استفاده از ابزارهای معروف و رایج و کارآمدی مانند: material-ui , redux , react-final-form .سرعت بسیار عالی.قابلیت بازگردانی عمل حذف و ویرایش در مولفه ی لیست آن به مدت چند ثانیه.اعتبارسنجی داده های دریافتی از شبکه.قابلیت ترجمه به زبان های مختلف(i18n یا همون internationalization که من خودم وقتی از این قابلیت استفاده کردم واقعا برام جذاب بود. مخصوصا اینکه فارسی رو هم پشتیبانی می کنه و تو داکش هم ابزار لازم برای پیاده سازی کلمات بصورت فارسی رو قرار داده که به نظر من با وجود این تحریم ها، خیلی جالب بود.)بصورت باورنکردنی ای قابل شخصی سازی شدنه، مخصوصا اینکه از material-ui استفاده می کنه، انعطاف بسیار بالایی در customize شدن داره. این موضوع جایی خودشو بهتون نشون میده که می خواید همه چیز رو راست چین کنید(چون سایت های فارسی باید راست چین باشن)، ظاهر وبسایت رو تغییر بدین و....یه dataprovider داره که کارای مربوط به ارسال و دریافت داده به/از سرور رو بصورت خودکار و در پشت صحنه انجام میده، یعنی شما یکی از پکیج های npm ای رو که داخل داک این قالب هست انتخاب می کنید و ازش استفاده می کنید و دیگه نگران این نیستید که الان باید درخواست بدم به سرور و رسپانس رو دریافت و پردازش کنم. خودش درخواست رو ارسال می کنه و دریافت و کنه و خودش هم داده ها رو داخل لیست قرار میده و نمایش میده. ضمن اینکه شما می تونید dataprovider دلخواه خودتون رو پیاده سازی کنید و به داشبوردتون بدید.یه مولفه ای به نام datagrid داره که یه سری امکانات مثل sort , filter , pagination رو خودش انجام میده با یه دکمه که تو ui اش هست.شخصی سازی ظاهر داشبورد.و...اما یه نکته ای که هست، یه ایراد خیلی بزرگ داره که اون هم بعضی جاها برای عوض کردن استایل ها (کدهای css) و override کردن اون ها یکم اصطکاک وجود داره و این کار سخت انجام میشه که اون هم بیشتر مربوط به وقتی میشه که ما می خوایم  ظاهر و استایل و کدهای css کامپوننت های material-ui رو اون طور که دلخواه خودمونه بازنویسی(override) کنیم.درکل با توجه به اینکه مطالب فارسی کمی درباره ی این ابزار منتشر نشده بود ولی حس می کردم که ایرانی ها درحال استفاده از اون هستن ولی مطلب چندانی درموردش منتشر نکردن، خواستم توضیحاتی درمورد اون بنویسم. انشاا... که مفید باشه.تشکر.</description>
                <category>علی مقیمی</category>
                <author>علی مقیمی</author>
                <pubDate>Mon, 14 Mar 2022 00:00:19 +0330</pubDate>
            </item>
            </channel>
</rss>