<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های Sam Aghapour</title>
        <link>https://virgool.io/feed/@samAghapour</link>
        <description>درباره ی تکنولوژی های حوزه ی جاوااسکریپت مینوسیم</description>
        <language>fa</language>
        <pubDate>2026-06-16 08:07:43</pubDate>
        <image>
            <url>https://static.virgool.io/images/default-avatar.jpg</url>
            <title>Sam Aghapour</title>
            <link>https://virgool.io/@samAghapour</link>
        </image>

                    <item>
                <title>اصول SOLID در ری اکت: راهی برای نوشتن کامپوننت های با کیفیت تر</title>
                <link>https://virgool.io/@samAghapour/solid-principles-in-react-qnnzmtpj3ghy</link>
                <description>SOLIDبه مرور زمان که برنامههای React بزرگتر میشن، ممکنه که بخاطر نوشتن کد های بد اوضاع یکم بیریخت شه؛ کامپوننتهای پر از کد(تا چند صد خط!)، نگهداری سخت و باگهای غیرمنتظره. اینجاست که اصول SOLID به کار میان. این اصول که در اصل برای برنامهنویسی شیگرا طراحی شدن، بهمون کمک میکنن کد تمیز، انعطافپذیر و مقیاسپذیر بنویسیم. تو این مقاله، هرکدوم از این اصول رو توضیح میدم و نشون میدم چطور میتونیم ازشون تو React استفاده کنیم تا کامپوننتهامون مرتب، نگهداریشون راحتتر و آماده ی بزرگتر شدن باشن.کلمه ی SOLID مخفف پنج اصل طراحی هست که هدفشون نوشتن کد تمیز، قابل نگهداری و مقیاسپذیره.حرف S : اصل Single responsibility یا تک مسئولیتی میگه که هر کامپوننت باید فقط یک وظیفه داشته باشه.حرف O : اصل Open/Closed یا باز و بسته  میگه که کامپوننت ها باید برای گسترش باز باشن (قابلیت ارتقاي راحت) اما برای تغییر بسته باشن (نباید نیاز به تغییر در کد اصلی باشه).حرف L: اصل Liskov Substitution یا جایگزینی لیسکو میگه که کامپوننتها باید بتونن توسط کامپوننتهای فرزندشون  جایگزین بشن، بدون اینکه عملکرد اپلیکیشن خراب بشه.حرف I: اصل Interface segregation یا جداسازی رابط میگه که کامپوننتها نباید مجبور بشن به عملکردهای اضافی که نیازی ندارن وابسته بشن (پراپ هایی دریافت بکنن که بهش نیاز ندارن).حرف D: اصل Dependency Inversion یا وارونگی وابستگی میگه که کامپوننتها باید به انتزاعات وابسته باشن، نه پیادهسازیهای مشخص.اصل Single Responsibility Principle (SRP)فرض کنید یه ربات اسباببازی دارید که فقط میتونه یه کار انجام بده، مثلاً راه رفتن. اگه ازش بخوایم کار دوم مثل حرف زدن انجام بده،بعد مثلا کار سوم بخوایم پشتک زدن انجام بده و... خب گیج میشه چون باید روی راه رفتن تمرکز کنه و کارش همون راه رفتن باشه! اگه کار دیگهای میخواید، باید یه ربات دیگه بگیرید.تو React هم همینطوره خب؛ یه کامپوننت باید فقط یه کار انجام بده. اگه چندتا کار مثل گرفتن دیتا، مدیریت فرم و نمایش UI رو همزمان انجام بده، کامپوننتمون خیلی شلوغ  وکثیف و مدیریتش سخت میشه.  const UserCard = () =&gt; {
  const [user, setUser] = useState(null);

  useEffect(() =&gt; {
    fetch(&#039;/api/user&#039;)
      .then(response =&gt; response.json())
      .then(data =&gt; setUser(data));
  }, []);

  return user ? ( &lt;div&gt;
      &lt;h2&gt;{user.name}&lt;/h2&gt;
      &lt;p&gt;{user.email}&lt;/p&gt;
    &lt;/div&gt; ) : &lt;p&gt;Loading...&lt;/p&gt;;
};در کد بالا مشکلی که هست اینه که کامپوننت userCard هم مسئولیت فچ کردن دیتا و هم نشون دادن دیتا رو بر عهده داره و به مرور ممکنه حتی فچ های بیشتری انجام بده و... که خب این کد باعث میشه اصل تک مسئولیتی شکسته شه.const useFetchUser = (fetchUser) =&gt; {
  const [user, setUser] = useState(null);

  useEffect(() =&gt; {
    fetchUser().then(setUser);
  }, [fetchUser]);

  return user;
};

const UserCard = ({ fetchUser }) =&gt; {
  const user = useFetchUser(fetchUser);

  return user ? (
    &lt;div&gt;
      &lt;h2&gt;{user.name}&lt;/h2&gt;
      &lt;p&gt;{user.email}&lt;/p&gt;
    &lt;/div&gt;
  ) : (
    &lt;p&gt;Loading...&lt;/p&gt;
  );
};حالا در کد بالا ما فچ کردن رو بردیم توی یه هوک کاستوم و توی کامپوننت userCard دیگه کاری با فچ کردن دیتا نداریم و هوک این وظیفه رو برعهده داره و ما فقط دیتارو ازش میگیریم و به عنوان وظیفه ی این کامپوننت نشون میدیم.اصل Open/Closed Principle (OCP)فرض کنید یه شخصیت توی بازی ویدیویی دارید. میتونید به این شخصیت مهارتهای جدید اضافه کنید (گسترش)، بدون اینکه تواناییهای اصلیش تغییر کنه (تغییرات). اصل OCP دقیقاً همینو میگه؛ یعنی اجازه بدید کدتون رشد کنه و قابلیتهاش رو بیشتر کنید، بدون اینکه مجبور باشید چیزای قبلی رو تغییر بدید(بدون اینکه اصل کد رو دست بزنید.const Alert = ({ type, message }) =&gt; {
  if (type === &#039;success&#039;) {
    return &lt;div className=&amp;quotalert-success&amp;quot&gt;{message}&lt;/div&gt;;
  }
  if (type === &#039;error&#039;) {
    return &lt;div className=&amp;quotalert-error&amp;quot&gt;{message}&lt;/div&gt;;
  }
  return &lt;div&gt;{message}&lt;/div&gt;;
};اینجا هر بار که نیاز به نوع جدیدی از هشدار داشته باشید، باید کامپوننت Alert رو تغییر بدید، که این اصل OCP رو نقض میکنه. هر وقت تو کامپوننتتون از conditional rendering  یا switch استفاده کنید، نگهداری اون سختتر میشه، چون در آینده مجبورید شرایط بیشتری اضافه کنید و کد اصلی اون کامپوننت رو تغییر بدید که این کار اصل OCP رو میشکنه.const Alert = ({ className, message }) =&gt; (
  &lt;div className={className}&gt;{message}&lt;/div&gt;
);

const SuccessAlert = ({ message }) =&gt; (
  &lt;Alert className=&amp;quotalert-success&amp;quot message={message} /&gt;
);

const ErrorAlert = ({ message }) =&gt; (
  &lt;Alert className=&amp;quotalert-error&amp;quot message={message} /&gt;
);حالا کامپوننت Alert برای گسترش بازه (با اضافه کردن چیزایی مثل SuccessAlert، ErrorAlert و غیره) ولی برای تغییر بسته است، چون برای اضافه کردن نوع جدید هشدار نیازی به دست زدن به کد اصلی کامپوننت Alert نداریم.اگه میخواید اصل OCP رو رعایت کنید، به جای inheritence از composition استفاده کنید و تا حد ممکن از شرطی رندر کردن توی کامپوننت هاتون دوری کنید.اصل Liskov Substitution Principle (LSP)فرض کنید یه تلفن معمولی دارید و بعد یه گوشی هوشمند میخرید. انتظار دارید همونطور که با تلفن معمولی تماس میگرفتید، با گوشی هوشمند هم بتونید تماس بگیرید و حالا یه سری کارای پیشرفته ی جدید هم بکنید. حالا اگه گوشی هوشمند نتونه تماس بگیره، یه جایگزین بد محسوب میشه و درواقع اصل رفتار یه گوشی هوشمند رو تغییر میده، درسته؟ اصل LSP همینو میگه؛ کامپوننتهای جدید یا فرزند باید مثل نسخه اصلی کار کنن، بدون اینکه چیزی رو خراب کنن یا رفتار پیشبینیشده رو تغییر بدن.const Button = ({ , children }) =&gt; (
  &lt;button ={}&gt;{children}&lt;/button&gt;
);

const IconButton = ({ , icon }) =&gt; (
  &lt;Button ={}&gt;
    &lt;i className={icon} /&gt;
  &lt;/Button&gt;
);در کد بالا IconButton یه ورژن دیگه از button هستش که ایکون هم داره توش ولی خب حالا ما این دکمه رو با کامپوننت Button عوض کنیم باید دقیقا مث همون کار بکنه با این تفاوت که ایکون هم داره حالا; ولی اینطور نیست چون کامپوننت IconButton چیزایی که Button میگیره (در این مثال label) رو نمیگیره پس رفتار رو تغییر میده.const Button = ({ , children }) =&gt; (  &lt;button ={}&gt;{children}&lt;/button&gt;);const IconButton = ({ , icon, label }) =&gt; (  &lt;Button ={}&gt;    &lt;i className={icon} /&gt; {label}  &lt;/Button&gt;);// IconButton now behaves like Button, supporting both icon and labelحالا IconButton به درستی رفتار کامپوننت Button رو گسترش میده، هم icon و هم label رو پشتیبانی میکنه، بنابراین میتونید با کامپوننت Button جایگزینش کنید بدون اینکه عملکرد خراب بشه. این اصل Liskov Substitution Principle رو رعایت میکنه، چون کامپوننت فرزند IconButton میتونه جایگزین کامپوننت پدر Button بشه، بدون هیچ مشکلی!اگه کامپوننت B از A گسترش پیدا کنه، هر جا که از کامپوننت A استفاده میشه، باید بتونید کامپوننت B رو هم جایگزین کامپوننت A کنید بدون اینکه هیچ یک از عملکردهای A از بین بره.اصل Interface Segregation Principle (ISP)فرض کنید یه ریموت کنترل برای تماشای تلویزیون دارید٬ در این صورت شما فقط به چندتا دکمه برای خاموش و روشن کردن و بالا و پایین اوردن و تغییر کانال تلویزیون نیاز دارید و نه مثلا اینکه بیاید دکمه های خاموش روشن کردن چراغ خونه و رادیو و ماهواره و... رو هم با همون کنترل انجام بدید که کلی پیچیدگی به ریموت کنتترلتون اضافه میکنه.حالا تصور کنید یه کامپوننت DataTable (جدول داده) دارید که کلی پراپ میگیره حتی اگه همشون رو هم استفاده بکنه بازم دلیل بر این نمیشه که همشون رو نیاز داره!const DataTable = ({ data, sortable, filterable, exportable }) =&gt; (
  &lt;div&gt;
    {/* Table rendering */}
    {sortable &amp;&amp; &lt;button&gt;Sort&lt;/button&gt;}
    {filterable &amp;&amp; &lt;input placeholder=&amp;quotFilter&amp;quot /&gt;}
    {exportable &amp;&amp; &lt;button&gt;Export&lt;/button&gt;}
  &lt;/div&gt;
);داره این کامپوننت بالا باعث میشه که مصرف کننده به تمام این مسائل از حمله فیلریتگ و سورت کردن و اکسپورت کردن فک کنه حتی اگه فقط یه دیتای ساده بدون این فانشکنالیتی ها بخواد!اینجاس که شما باید کامپوننت رو به تیکه های کوچیک تر تقسیم کنید تا فقط پراپ های ضروری خودشون رو دریافت کنند.const DataTable = ({ data }) =&gt; (
  &lt;div&gt;
    {/* Table rendering */}
  &lt;/div&gt;
);

const SortableTable = ({ data }) =&gt; (
  &lt;div&gt;
    &lt;DataTable data={data} /&gt;
    &lt;button&gt;Sort&lt;/button&gt;
  &lt;/div&gt;
);

const FilterableTable = ({ data }) =&gt; (
  &lt;div&gt;
    &lt;DataTable data={data} /&gt;
    &lt;input placeholder=&amp;quotFilter&amp;quot /&gt;
  &lt;/div&gt;
);حالا هر جدول فقط ویژگیهایی رو شامل میشه که واقعاً نیاز داره و پراپزهای غیرضروری همه جا استفاده نمیشن. این  Interface Segregation principle (ISP) رو رعایت میکنه، جایی که کامپوننتها فقط به بخشهایی وابسته هستن که واقعاً نیاز دارن.اصل Dependency Inversion Principle (DIP)فرض کنید با بلوکهای LEGO دارید یه رباتی میسازید. اگه بخواید دست یا پاهای ربات رو عوض کنید، نباید کل ربات رو دوباره بسازید که! فقط اون قسمتها رو جایگزین میکنید. اصل DIP هم همینو میگه: کامپوننتهای اصلی نباید به جزئیات خاص وابسته باشن، بلکه باید به قطعات قابل تغییر تکیه کنن.const UserComponent = () =&gt; {
  useEffect(() =&gt; {
    fetch(&#039;/api/user&#039;).then(...);
  }, []);
  return &lt;div&gt;...&lt;/div&gt;;
};کد بالا مستقیما به fetch وابسته اس و خب اگه مثلا بخوایم توی محیط تست بجای این فچ از یه mock api ای چیزی استفاده کنیم یا دیتارو تغییر بدیم نمیتونیم اینکار رو بکنیم.const UserComponent = ({ fetchUser }) =&gt; {
  useEffect(() =&gt; {
    fetchUser().then(...);
  }, [fetchUser]);
  return &lt;div&gt;...&lt;/div&gt;;
};حالا تابع fetchUser بهعنوان یک پراپز پاس داده شده (یا میتونیم از جای دیگه ایمپورتش کنیم اصن) و بهراحتی میتونیم اون رو با یه پیادهسازی دیگه (مثلاً یک API شبیهسازیشده یا منبع داده دیگه) جایگزین کنیم. این کار انعطافپذیری و تستپذیری کد رو بالا میبره.جمع بندی نهاییدرک و استفاده از اصول SOLID توی React میتونه کیفیت کدتونو بهطرز چشمگیری بهتر کنه. این اصول بهتون کمک میکنن کامپوننتایی بنویسید که ماژولارتر، منعطفتر و راحتتر نگهداری بشن. در نهایت، اصول SOLID باعث میشن کدهاتون تمیزتر و پایدارتر باشن.ممنون که تا اینجای مقاله همراهی کردید و امیدوارم کدای باکیفیت تر و خفن تری بنویسید.تا مقاله بعد خدانگهدار و موفق باشید🤞🏻</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Sat, 28 Sep 2024 20:03:03 +0330</pubDate>
            </item>
                    <item>
                <title>استراتژی های کش کردن دیتا در Next.js برای افزایش سرعت وب اپلیکیشن ها</title>
                <link>https://virgool.io/@samAghapour/caching-strategies-in-nextjs-yicwr1kupjm9</link>
                <description>کشینگ توی Next.js فقط برای صرفه‌جویی در زمان نیست — این کار باعث میشه درخواست‌های تکراری شبکه رو کم کنید، داده‌ها رو همیشه تازه نگه دارید، حالا چه بخواید داده‌هاتون رو برای مدت طولانی توی کش نگه دارید یا فقط وقتی نیاز شد اون‌ها رو تازه کنید، Next.js همه ابزارهای لازم رو در اختیارتون میذاره. توی این مقاله، میخوایم یاد بگیریم چطور از کشینگ توی Next.js به بهترین شکل استفاده کنیم.فریمورک Next.js قابلیت‌های fetch API رو تقویت کرده تا دستتون رو توی کش کردن داده‌ها باز بذاره. با گزینه‌های ساده‌ای مثل cache: &#x27;no-store&#x27; و cache: &#x27;force-cache&#x27;، خیلی راحت می‌تونید مشخص کنید که داده‌هاتون چه زمانی و چطوری کش بشن.دیتای همیشه تازه با cache: &#x27;no-store&#x27;می‌خواید هر دفعه داده‌ها رو به‌روز و تازه بگیرید؟ cache: &#x27;no-store&#x27; انتخاب درستیه. این گزینه توی fetch کلاً کش رو نادیده می‌گیره و هر بار درخواست جدیدی می‌فرسته تا آخرین داده‌ها رو دریافت کنه. این گزینه زمانی که به دقت لحظه‌ای نیاز دارید فوق‌العادس.نکته: می‌تونید از unstable_noStore() هم استفاده کنید اگه می‌خواید کش رو توی یک کامپوننت نادیده بگیرید. اما دقت کنید که این سینتکس ممکنه در آینده تغییر کنه، پس بهتره برای پایداری از cache: &#x27;no-store&#x27; استفاده کنید.استفاده مجدد از دیتای از قبل کش شدهاز اون طرف، اگه مشکلی با استفاده از داده‌های کش‌شده ندارید (مثلاً برای محتوای استاتیک که زیاد تغییر نمی‌کنه)، cache: &#x27;force-cache&#x27; انتخاب خوبیه. این گزینه پاسخ رو ذخیره می‌کنه تا دفعه بعد بتونید ازش استفاده کنید و درخواست‌های اضافی شبکه رو نادیده می‌گیره.نکته: unstable_cache هم داده‌ها رو کش می‌کنه، اما استفاده از cache: &#x27;force-cache&#x27; که گزینه پایدارتره، اگه می‌خواید در آینده با مشکلات پیش‌بینی‌نشده مواجه نشید، انتخاب مطمئن‌تریه.جلوتر از این متدها هم مثال خواهم زد.در عکس بالا میبینیم که وقتی از force cache استفاده میکنیم برای بار اول که هنوز دیتایی کش نشده میره از سرور میگیره و تو راه برگشتش به کلاینت توی مموری کش میشه و دفعه ی بعد دیگه از همون مموری برمیداره و اصن ریکوست جدیدی سمت سرور نمیره.و وقتی که no store رو استفاده میکنیم کلا چه کش شده باشه چه نشده باشه مموری رو اسکیپ میکنه و میره مستقیم از سرور هر سری دیتای جدید میگیره.تازه نگه‌داشتن داده‌ها با ریوَلیداشن (Revalidation)گاهی اوقات داده‌های کش‌شده نیاز به یه بروزرسانی دارن — ممکنه بعد از یه مدت زمان خاص یا به خاطر یه رویداد خاص لازم بشه تازه بشن. خوشبختانه، Next.js چندین روش برای ریولید کردن (بروزرسانی) داده‌های کش‌شده در اختیار شما می‌ذاره.مثلا شما میای بلاگ پست هارو از مموری کش میگیری و نشون میدی و حالا یه بلاگ جدید که به دیتابیس اضافه بشه دیگه چون از مموری دیتای قدیمی کش شده رو برمیداریم این بلاگ پست جدید رو به ما همچنان نشون نمیده. اینجاس که باید یه مکانیسمی برای پاک کردن مموری کش داشته باشیم تا دیتای تازه رو از سرور بره بگیره.حالا اینکار رو میتونیم بگیم هر فلان ساعت/ فلان روز یبار انجام بده خودکار و یا میتونیم بگیم بعد از انجام عمل خاصی اینکار رو بکنه که هر دوش رو بررسی میکنیم.بروزرسانی با زمان: next.revalidateاگه داده‌های شما نیاز دارن که به‌صورت دوره‌ای (مثل هر ساعت یا هر روز) بروزرسانی بشن، می‌تونید از گزینه next.revalidate توی درخواست fetch استفاده کنید. این کار باعث میشه بعد از مدت زمانی که مشخص می‌کنید، آخرین داده‌ها رو بگیره، در حالی که بقیه‌ی زمان داده‌ها از کش استفاده می‌کنن.توی عکس بالا میبینیم که زمان بروزرسانی رو گذاشتیم رو ۶۰ ثانیه و حالا اگه در کمتر از ۶۰ ثانیه هرچندبار هم ریکوست زده بشه از مموری کش استفاده میکنه ولی اگه از ۶۰ ثانیه گذشته باشه میبینه دیتای توی مموری کهنه اس پس میره برای بروزسانی از سرور دیتای جدید میگیری برمیگردونه و تو راه اون دیتای جدید رو هم برای ۶۰ ثانیه بعدی کش میکنه.اینم مثال کدش:
fetch(&#039;https://api.example.com/data&#039;, {
  next: { revalidate: 3600 }  
  // Revalidate data every hour (3600 seconds)
});بروزرسانی داده‌ها به‌صورت آنی با تگ‌ها: revalidateTagحالا تصور کنید که می‌تونید به Next.js بگید تا بخش‌های خاصی از داده‌های کش‌شده رو فقط وقتی که یه اتفاق مهم می‌افته بروزرسانی کنه — مثلاً وقتی یه فرم ارسال میشه یا یه پست وبلاگ جدید منتشر میشه. شما می‌تونید به داده‌های کش‌شده‌تون تگ اختصاص بدید و هر وقت که لازم بود، اون تگ‌ها رو ریولید (بروزرسانی) کنید.توی عکس بالا میبینیم که به یکی از دیتاهامون یه تگ a دادیم و درواقع اسم گذاریش کردیم و بعدش هروقت متد revalidateTag رو صدا کنیم و اسم تگ دیتامون رو بدیم میره دیتاشو از مموری کش پاک میکنه تا سری بعد که همون دیتا دوباره ریکوست زده شد بره دیتای جدید از سرور بگیره بیاره.اینطوری می‌تونید بخش‌های خاصی از کش رو به‌صورت دستی و آنی بروزرسانی کنید، بدون اینکه منتظر زمان‌بندی بعدی برای ریولید شدن بمونید.استفاده از متدهای ناپایدار (Unstable Methods)اگه از اون آدمای کنجکاو هستید، می‌تونید مستقیماً از متدهای unstable_noStore و unstable_cache توی کامپوننت‌ها استفاده کنید تا کش رو مدیریت کنید. فقط یادتون باشه که این متدها به خاطر ناپایدار بودنشون ممکنه در آینده تغییر کنن (یا حتی شاید همین حالا که دارید اینو می‌خونید، تغییر کرده باشن سینتکسشون!).unstable_noStoreیا اگه طرفدار کشینگ هستید، اینم طرز استفاده از unstable_cache:unstable_cacheدیگه لازم نیست داده رو توی کامپوننت‌های مختلف بارها و بارها درخواست بدید!اگه توی چندین کامپوننت (مثل Layout، Page و چند تا کامپوننت داخلی) از همون داده استفاده می‌کنید، لازم نیست داده رو یک‌بار بالا بگیرید و هی به کامپوننت‌های دیگه پاس بدید یا مجبور باشید توی هر کامپوننت جداگانه درخواست بزنید که باعث کاهش سرعت بشه. نکست‌جی‌اس به‌طور خودکار درخواست‌های fetch رو توی سرور رندرینگ ذخیره می‌کنه، یعنی اگه همون داده رو چند بار درخواست کنید، فقط یک‌بار به شبکه دسترسی پیدا می‌کنه و نتیجه رو بین کامپوننت‌های مختلف به اشتراک می‌ذاره مگه اینکه برای اون دیتا از no-store استفاده کنید.توی کد بالا توی اولین فچ چون هنوز دیتاش توی مموری کش نشده میره از سرور میگیره میاره ولی دفعه ی دوم چه توی این کامپوننت چه توی هر کامپوننت دیگه ای همین ریکوست رو بزنی چون دیتاش توی مموری کش شده میره از اونجا برمیداره و ریکوستی سمت سرور نمیره که باعث افزایش سرعت اپلیکیشنتون میشه.جمع‌بندیفریمورک Next.js همه ابزارهای لازم رو برای مدیریت کشینگ به بهترین شکل در اختیارتون می‌ذاره؛ چه با استفاده از گزینه‌های fetch API مثل cache: &#x27;no-store&#x27; و cache: &#x27;force-cache&#x27;، یا با استفاده از متدهایی که هنوز پایدار نیستند مثل unstable_noStore و unstable_cache. با اضافه کردن استراتژی‌های بروزرسانی مثل next.revalidate و revalidateTag، همه چیز رو برای تازه نگه‌داشتن داده‌ها دارید، اونم بدون اینکه سختی بکشید یا برنامه‌تون کند بشه.منبع:داکیومنت caching در سایت رسمی Next.js</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Mon, 16 Sep 2024 13:02:19 +0330</pubDate>
            </item>
                    <item>
                <title>تمام چیزهایی که باید از React 19 بدونید</title>
                <link>https://virgool.io/@samAghapour/sam-aghapour-react19-exsijs0g7tnp</link>
                <description>ری اکت ۱۹ با یه سری تغییرات جدید و جذابی منتشر شده که توی این پست قراره بهشون بپردازیم.این تغییرات شامل فیچر های جدید٬ بهبود٬ حذف و یا جایگزینی فیچر های فعلی هستش.تغییراتی که باعث میشه ما به عنوان دولوپر با کد کمتر٬ خروجی بیشتر و بهتری بگیریم. تمام تغییراتی که در این پست دربارش صحبت میکنیم:1. React Compiler2. forwardRef =&gt; Ref as a prop3. Document Metadata4.Server Components5. Actions6. New Hooks (use(), useFormStatus(), useOptimistic(), کامپایلر ری اکتیکی از مشکلایی که توی ری اکت از زمان های خیلی دور وجود داشت ری رندر های اضافه اس که به پرفورمنس پروژه آسیب میزنه. این اصن منطقی نبود که وقتی پراپی که میگیریم تغییری نکرده٬ بیایم کامپوننت رو ری رندر بکنیم صرفا برای اینکه کامپوننت پدر ری رندر شده. حالا فک کنید کلی کامپوننت تو در تو داشتیم که اینا هیچ کدوم نیاز به ری رندر نداشتند چون اصلا پراپشون تغییری نکرده اما فقط چون کامپوننت پدر ری رندر شده همه ی این کامپوننت ها هم ری رندر میشدن و سرعت وبسایت رو میاوردن پایین.برای حل این مشکل تیم ری اکت تکنیک هایی رو معرفی کرد تا بتونیم با استفاده ازشون دیتایی که به عنوان پراپ پاس داده میشن رو به اصطلاح به یادسپاری یا memoize کنیم تا از ری رندر اضافه جلوگیری کنیم.این تکنیک ها استفاده از useMemo, useCallback, Memo بود.اما مشکلی که این روش داره اینه که اولا واقعا خیلیا نمیدونن دقیقا چه موقعی مناسبه این تکنیک هارو استفاده کنند و ممکنه اون ری رندر ارزشش رو نداشته باشه و بدتر به پرفورمنس آسیب بزنه از اونجایی که خود این هوک ها یه پروسه ی مقایسه ی پراپ قبلی و  پراپ جدید دارند. ( اطلاعات بیشتر رو میتونید توی این مقاله که درباره بهبود پرفورمنس پروژه های ری اکتی نوشتم بخونید)دوما که تجربه دولوپر یا Developer Experience  جالبی هم ندارن بنظرم.حالا بعد از کلی فیدبک از کامیونیتی و صرف زمان زیاد٬ تیم ری اکت بلخره اعلام کردند که روی کامپایلر ری اکت کار کردند و دارند روی اینستاگرام استفادش میکنند و بزودی توی ورژن های بعدی ریلیزش میکنند.این کامپایلر میاد کد ری اکت شمارو به جاوااسکریپت خالص تبدیل میکنه و در پشت پرده خودش اون پروسه ی بهبود پرفورمنس و memoization رو انجام میده که دیگه شما نیازی به استفاده از اون هوک ها نباشید.پس به این ترتیب useCallback , useMemo و memo به همین راحتی از ری اکت پر پر میشن و کار رو برای ما ساده تر میکنند.از این پس Ref به عنوان پراپ پاس داده میشودما قبلا وقتی یه متغیر داشتی که برابر با useRef بود و اگه میخواستیم این متغیر رو پاس بدیم به یه کامپوننت فرزند تا اونجا استفاده بشه از forwardRef استفاده میکردیم تا بتونیم علاوه بر پراپ ها اون رفی که پاس داده شده رو هم بگیریم استفاده کنیم. به این شکل:اما حالا دیگه نیازی به این کار نیست و مستقیم میتونیم رف رو به عنوان پراپ پاس بدیم. به این شکل:پس به این صورت به forwardRef هم دیگه نیازی نیست.پشتیبانی از MetaDataتوی ورژن های قبلی ری اکت هر وقت میخواستیم تو jsx یه کامپوننت یه سری تگ به هد اضافه کنیم مجبور بودیم از لایبرری هایی مثل React Helmet استفاده کنیم ولی الان میتونیم مستقیم تو jsx تگای متا و لینک و.. که برای هد هستن رو بزاریم و خود ری اکت به صورت اتوماتیک میاد تشخیصشون میده و برشون میداره میزاره تو  تگ head:کامپوننت های سمت سرورمبحث server component  و client component مدت زیادیه که هست و توی Next.js ازش زیاد استفاده میکنیم.به طور کل کامپوننت های سرور ساید کامپوننت هایی هستند که سمت سرور موقع بیلد ساخته میشن و با قرار نگرفتن در باندل جاوااسکریپت باعث کاهش سایز اون و بهبود پرفورمنس میشند و یه سری مزایای دیگه هم دارند:۱. بهبود SEO: کامپونننت های سرور ساید چون سمت سرور ساخته رندر میشند و به صورت html اماده ریترن میشن٬ crawler های  سرچ انجین به محتوای بیشتری دسترسی دارند و همین باعث بهبود seo میشه . تو کدای سمت client چون کامپوننت ها سمت کلاینت ساخته میشند و توسط جاوااسکریپت  به طور داینایک محتوای صفحه رو اپدیت میکنند اولش هیچ محتوایی وجود نداره و page source خالیه و crawler ها هیچی پیدا نمیکنند.۲. بهبود پرفورمنس: همونطور که تو مورد اول اشاره شد چون کامپوننت های سرور ساید موقع بیلد سمت سرور ساخته یا pre-built میشند سرعت لودشون بسیار بالاست و نتیجتا پرفورمنس بهتری دارند.۳. امنیت : سرور کامپوننت ها اجازه میدند که دیتای حساسمون مثل توکن ها و api key ها سمت سرور بمونند و در سمت کلاینت قابل دسترس نباشند که امنیت سایت رو بالاتر میبره.حالا اینا مزایای درشتش بود و اگه فقط همینارو در نظر بگیریم ری اکت با دیفالت کلاینت ساید بودنش در ورژن های قبلی مزیت های بزرگی رو از دست میداد که توی ورژن اخیر server component رو اضافه کرد. هرچند برخلاف نکست٬ ری اکت کامپوننت ها بای دیفالت هنوز کلاینت ساید هستند و اگه بخوایم سرور ساید رندر بشند باید به خط اول کامپوننتمون دایرکتیوی به این شکل اضافه کنیم&#039;use server&#039;;
import React from &#039;react&#039;;
...اکشن هااکشن ها قابلیت جدیدی هستن که به ری اکت اضافه شدند و نحوه ی کارکردن با فرم ها توی ری اکت رو تغییر میدن. ما قبلا از   روی دکمه ی سابمیت در فرم استفاده میکردیم و همچنین استیت هایی برای دسترسی به مقادیر اینپوت های داخل فرم نیاز داشتیم تا دیتای فرم رو سابمیت کنیم الان با استفاده از اتربیوت action روی تگ form میتونیم دیتاشو بگیریم و سابمیت کنیم به این شکل:همونطور که میبینید action برابر یه فانکشن هستش که دیتای توی اون فرم رو توی پارامتر اول بهمون برمیگردونه و میتونیم با متد get ای که داره اسم هر اینپوت داخل فرم رو بهش بدیم و مقدار سابمیت شده رو بگیریم.تو سکشن بعد هوک های جدیدی که اضافه شده رو معرفی کنم شاهد بهبود های حتی بیشتری هم در هندل کردن فرم ها خواهیم بود.هوک های useFormState و useFormStatusاین دو هوک های جدیدی هستند که به ری اکت اضافه شدند تا کار با فرم هارو برامون راحت تر کنند.useFormState():این هوک بهمون اجازه میده که یه استیتی داشته باشیم و مقدار اون استیت رو بر مبنای ریزالتی که توی اون هندلر اکشن فرم ریترن میکنیم٬ ست کنیم.  بیاید یه مثال ببینیم:کد بالا حالتیه که توش از اکشن و هوک useFormState استفاده نشده و میبینیم که سه تا اینپوت تعریف شده برای اینپوت ها و مسیج که از ریکوستمون برمیگرده.حالا همین رو با استفاده از اکشن و هوک useFormState مینویسیم:توی کد بالا استیت ها حذف شدن چون دیگه پارامتری که هندلر فرم اکشن برمیگردونه دیتای name و email رو توش داره و برای مسیج هم از هوک useFormStatus استفاده شده.این هوک مثل استیت یه ارایه برمیگردونه که مقدار اولش مقداریه که از اکشنش ریترن میشه و مقدار دومش همون فانکشن اکشنش هست که میزاریمش توی اتریبیوت action فرممون. مقادیری که هوک میگیره هم اولیش فانشکنیه که میخوایم موقع اکشن فرممون صداش کنیم و چیزی ک برمیگردونه میره تو همون message قرار میگیره و مقدار دومی که میگیره initial Value ای هست که میخوایم message داشته باشه.useFormStatus():فک کنید میخوایم ارور و لودینگ هم به فرممون تو مثال بالا اضافه کنیم. بیاید اول با روال سابق کدش رو ببینیم:حالا بیاید با استفاده از اکشن و هوک های جدیدمون ببینیم:توی کد میبینیم که دکمه ی سابمیت رو بردیم توی یه کامپوننت جدا و اونجا از هوک useFormStatus استفاده کردیم که این هوک یه ابجکت برمیگردونه که شامل پراپرتی های data و panding و یه سری پراپرتی های دیگه که خیلی کاربردی ندارن هستش.پراپرتی data همون دیتاییه که از فرم بدست اومده و سابمیت شده و پراپرتی پندینگ هم یه بولین هست که تا زمانی که فرم اکشنمون ریزالتی برنگردونه و پندینگ باشه این پراپرتی ترو هست و بعد با موفقیت یا شکست پرامیس اکشنمون٬ پراپرتی pending فالس میشه.نکته: یکی از بدی های این هوک اینه که نمیتونی توی همون همون هوکی که فرم وجود داره استفادش کنی و این هوک فقط وضعیت فرم کامپوننت پدر رو بهتون میده:دیگه هوک جدید چی داریم؟!هوک use:این هوک که تازه به ری اکت اومده چند کاره اس و کارش آسون تر کردن روند گرفتن دیتا از سورس خارجی و همینطور کانتکست هستش:گرفتن دیتا از سورس خارجیجوری که قبلا دیتا رو میگرفتیم:ما نیاز به یه استیت داشتیم و همینطور یه یوزافکت که دیتارو داخلش فچ کنیم و توی استیت ست کنیم.حالا با هوک uas نیازی به استیت و یوزافکت نداریم :حالا یه چیز باحال تر که میتونیم انجام بدیم که user experience بهتری داشته باشیم اضافه کردن یه لودینگ هست تا وقتی که دیتا فچ میشه. مطمعنا میدونید که توی روال قبلی باید یه استیت لودینگ هم اضافه میکردیم ولی اینجا با استفاده از suspense ری اکت کار رو برامون راحت تر کرده:با پیچیدن کامپوننت Suspense دور کامپوننتمون و اضافه کردن یه لودینگ به عنوان fallback این کامپوننت تا زمانی که دیتارو نگرفته بهمون لودینگ رو نشون میده که این بهبود assets loading توی ورژن جدید ری اکت رو نشون میده و به نوعی میتونیم اینو پایان React.lazy هم بدونیم نه فقط بخاطر این کیس بلکه بخاطر اضافه شدن server componet ها و pre-render شدن سمت سرور و.. که تا حدی مارو بی نیاز از react.lazy میکنه.۲. استفاده دوم از use برای گرفتن دیتا از کانتکست هستش.قبلا از هوک useContext توی کامپوننت ها استفاده میکردیم تا دیتای موجود در کانتکستمون رو بخونیم :الان از همون use هم میتونیم استفاده کنیم:این خیلی فرق بزرگی ایجاد نکرده ولی در کل اگه دارید توی یه کامپوننت از use استفاده میکنید میتونید ازش برای خوندن کانتکست هم استفاده کنید و نیاز نباشه یه هوک دیگه هم ایمپورت کنید.نکته: توی ورژن جدید ری اکت بجای &lt;/ Context.Provider&gt; از &lt;/ Context&gt; استفاده میشه و نیازی به گذاشتن اون کلمه ی provider نیست.هوک UseOptimisticاین هوک تو جاهایی که نیاز به اینتراکشن با سرور دارید مثل برنامه های real-time  به درد میخوره. مثلا فک کنید وقتی یه پستی رو لایک میکنید دارید درواقع به سرور یه دیتایی میفرستید که اون لایک رو ثبت کنه یا مثلا وقتی پیامی میفرستید به کسی درواقع به سرور دارید دیتایی میفرستید که اون پیا رو ثبت کنه و توی چت باکس پیامش رو نشون بدیم. حالا فک کنید ممکنه چند ثانیه طولبکشه تا این لایکه یا پیاه به سرور برسه و موفق شه٬ این وسط یوزر قراره ببینه که با لایک یا فرستادن پیام هیچ اتفاقی نمیفته! نه پست لایک میشه نه پیام فرستاده میشه..اینجاس که با این هوک یه اپدیت خوشبینانه انجام میدیم به این صورت که با کلیکش میایم فرض رو بر این میگیریم که دیتا رفت تو سرور ثبت شد پس خودمون قبل اومدن دیتای اپدیت شده از سرور٬ میایم یه دیتای فیک وارد میکنیم که انگار از سرور اومده و موفق بوده و کاربر درجا میبینه که لایک شد. حالا وقتی دیتای واقعی از سرور اومد دیتای فیک مارو جایگزین میکنه و کاربر متوجهش نمیشه و چون به محض لایک میبینه که پست لایک شده و با اومدن دیتای واقعی دیتا تغییری نمیکنه. یا مثلا پیام رو که میفرسته ما اون پیام رو ثبت شده در نظر میگیریم و درجا تو چت باکس نشونش میدیم تا کاربر فک کنه که که پیامش ثبت شده. به این روش میگن اپدیت  optimistic یا خوشبینانه همونطور که از اسم هوکش پیداس.توی مثال بالا میبینیم که یه استیت messages داریم که مسیجای واقعی رو توش داره و هوک useOptimistic رو داریم که دوتا پارامتر میگیره اولی همون مقدار initial اش هست که برابر با همون مسیجای واقعی هستشو یه کال بک میگیره که به صورت خوشبینانه بیاد مسیجای قبلی رو به اضافه مسیج فیک خودمون برگردونه. این هوک یه ارایه شامل دوتا مقدار برمیگردونه اولیش همون دیتاییه که از کال بک ریترن میشه و دومیش همون کال بکه هستش که بتونیم جایی که میخوایمش صداش کنیم و خوشبینانه دیتارو اپدیت کنیم.توی jsx بجای مسیج های اصلی روی مسیج های optimistic یا همون optimisticMessages مپ میریم تا چون این علاوه بر مسیجای قبلی مسیج فیک ما هم شاملش میشه در حالی که استیت messages دست نخورده اس. حالا یه فرم داریم که اینپوت مسیج رو داره و وقتی کاربر مسیجش رو مینویسه و سابمیت میکنه داخل فانکشن sendMessage میبینیم که اول میاد اون فانکشن خوشبینانمون رو صدا میزنه و مسیج رو بهش پاس میده تا optimisicMessages رو اپدیت و در نتیجه سریع UI رو اپدیت کنه و بعد مسیج رو میفرسته سمت سرور که دیتای اصلی رو اپدیت کنه و وقتی دیتا برگشت حالا messages که حاوی دیتای اصلی هستش رو اپدیت میکنه و باعث میشه که optimisticMessages هم با دیتای واقعی رفرشبشه و اون فیکه با مسیج واقعی جایگزین بشه.این بود تمام تغییرات بزرگی که در ری اکت ۱۹ شاهدش بودیم.امیدوارم که بدردتون بخوره و لذت برده باشید. </description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Sat, 04 May 2024 21:47:26 +0330</pubDate>
            </item>
                    <item>
                <title>مدیریت ریکوئست ها با React Query در React</title>
                <link>https://virgool.io/@samAghapour/react-query-nbe8uawdcya2</link>
                <description>React Queryیکی از لایبرری های محبوب جاوااسکریپت که توی ری اکت خیلی ازش استفاده میشه  React Query هستش، این لایبرری ابزارای زیادی رو برای fetch کردن، cache کردن و update کردن دیتا از ‌API در اختیار ما میزاره و به ما کمک میکنه با مدیریت صحیح و بهینه ی ریکوئست هامون اپلیکیشن های پر سرعت و روان و تر تمیزی داشته باشیم.فواید کلیدی این لایبرری که هر برنامه نویسی رو وسوسه میکنه تا باهاش کار کنه:آسان تر کردن مدیریت دیتا: React Query مدیریت دیتای ریموت در اپلیکیشن ما با در اختیار گذاشتن ابزارهای خفنی برای fetching, caching و updating دیتا، سناریو های پیچیده مدیریت دیتا مثل paginations , optimistic updates و server-side rendering رو آسون تر میکنه.بهتر کردن پرفورمنس اپلیکیشن: React Query با کش کردن و Refetch کردن هوشمندانه ی دیتا فقط زمانی که به اینکار نیاز داریم، با کم کردن مقدار ریکوئست های غیر ضروری تاثیر زیادی در پرفورمنس اپلیکیشن ما میزاره.از بین بردن کد های غیرضروری: ‌ React Query مارو از نوشتن کدای غیر ضروری برای مدیریت دیتا بی نیاز میکنه که باعث حفظ زمان بیشتری میشه و به برنامه نویس این امکان رو میده که روی منطق پروژه و کامپوننت ها تمرکز داشته باشه و هیچ نگرانی درباره ی گرفتن و کش کردن دیتا نداشته باشه.آپدیت لحظه ای: React Query با استفاده از کانکشن های websocket و مابقی API های استریم، به ما این امکان رو میده تا آپدیت لحظه ای دیتارو داشته باشیم و نیازی نباشه کاربر رو برای اپدیت کردن دیتا مجبور به ریفرش صفحه بکنیم.توی این مقاله میریم سراغ قابلیت های کلیدی این لایبرری و بهتون نشون میدم که چطور میتونیم از این لایبرری استفاده کنیم، همچنین درباره server states و client states میخونیم و به این سوال که آیا React Query میتونه ابزار مفیدی برای global state manegement هم باشه پاسخ میدم.نحوه ی نصب:npm install react-query  بعد از نصب پکیج باید به شکل زیر عمل کنید:دقیقا مثل تصویر بالا، در فایل  index اقدام به ایمپورت کردن  QueryClientProvider و  QueryClient میکنیم که یه queryClient میسازیم و به عنوان پراپ client پاس میدیمش به  QueryClientProvider که پیچیدیمش دور کامپوننت App و حالا میتونیم راحت تو کامپوننت هامون از react query استفاده کنیم.useQueryاین هوک از مهم ترین هوک هایی هست که React Query در اختیارتون میزاره و خیلی باهاش کار میکنید. از این هوک برای فچ کردن دیتا از سرور و کش کردن اون دیتا برای سری های بعدی استفاده میشه:useQueryهمونطور که توی مثال بالا میبینید این هوک یه آبجکت به ما برمیگردونه که ما با دی استراکچر کردن هر کدوم رو ازش میکشیم بیرون تا استفادشون کنیم. پارامتر هایی که باید به این هوک بدیم اولی query key هستش که ازش برای اسم گذاری استفاده میکنیم. ینی چی؟ ینی بهش میگیم بیا به این اندپوینت فلان ریکوئست بزن و دیتاشو با این اسم( توی مثال با اسم todos) کش بکن که اگه بعدا خواستم دیتاشو اپدیت کنم و ازم اسم خواستی من به همین اسم اشاره بکنم که بتونی بشناسیش و آپدیتش کنی.دومین پارامتری که باید بهش پاس بدیم یه فانکشن async هست که توش ریکوئست رو میزنیم و دیتارو برمیگردونیم.حالا چیزایی که این هوگ برمیگردونه مهم تریناش همین ها هستند که دارین در تصویر بالا مشاهده میکنید.پراپرتی data شامل دیتایی هست که از ریکوئستمون با موفقیت بهمون برگشته، پراپرتی isLoading یه مقدار boolean هستش که اگه ریکوئستمون هنوز دیتارو نداده و در حالت pending هستش این پراپرتی true خواهد بود و در غیر این صورت false، پراپرتی isError هم دقیقا به همین صورته که تا وقتی که ریکوئستمون در حالت انتظار یا موفقیت باشه مقدار این پراپرتی false خواهد بود و فقط در صورتی که ریکوئستمون ارور برگردونه این پراپرتی true میشه. همچنین یه پراپرتی Error هم داریم که ازش میتونیم برای نشون دادن مسیج ارور Error.message استفاده بکنیم که توی مثال بالا نیست.نکته ی خفنش اینجاس که این data وقتی با موفقیت پر بشه و ما دیتارو داشته باشیم دفعات بعد این دیتا کش شده و وقتی کاربر دیتارو بخواد ببینه بدون لحظه ای لودینگ و درنگ میتونه دیتارو ببینه درحالی که React Query عزیز اون پشت داره ریکوئست تازه ای میزنه تا ببینه اگه دیتا عوض شده بود با این دیتای کش شده جایگزینش کنه و در غیر اینصورت دیتا تغییری نمیکنه.به همین راحتی دارید دوتا از قابلیتای کلیدی این لایبرری رو در همین مثال اول میبینید: یک اینکه ما خیلی راحت ریکوئستمون رو مدیریت میکنیم و برای هر سناریویی از جمله وقتی ریکوئستمون ارور بده یا موفق باشه یا لودینگ باشه، دستمون پره که این دنباله ی قابلیت کلیدی بعدی این لایبرری هستش که باعث میشه ما دیگه برای ریکوئسمون استیت های اضافی برای لودینگ و ارور و try catch های بیخود و... ننویسیم و کد رو بهینه تر و تمیز تر میکنه.useMutationاز این هوک وقتی استفاده میکنیم که میخوایم دیتارو تغییر بدیم مثلا وقتی که میخوایم یه ایتم به دیتا اضافه یا یه ایتم از دیتا حذف یا دیتای فعلی رو تغییر بدیم:useMutationهمونطور که توی مثال بالا میبینید این هوک هم یه آبجکت به ما برمیگردونه که ما با دی استراکچر کردن هر کدوم رو ازش میکشیم بیرون تا استفادشون کنیم. پارامتر هایی که باید به این هوک بدیم اولی فانکشن async هستش که توش ریکوئستمون رو میزنیم و دیتارو برمیگردونیم اگه این فانکشنمون نیاز به پارامتر داشته باشه(که توی مثال بالا newTodo هستش) اون پارامتر رو موقع صدا کردن mutate بهش پاس میدیم.پارامتر دومی که این هوک میگیری یه ابجکته که میتونیم توش با توجه به پراپرتی هایی که داره کارای مختلفی انجام بدیم، توی مثال بالا از پراپرتی onSuccess استفاده کردیم این متد وقتی که ریکوست موفقیت آمیز باشه صدا زده میشه و توی این متد میتونیم دیتای آپدیت شدمون رو دوباره Refetch یا invalidate کنیم. ینی چی؟ ینی به React Query بگیم دیتای من آپدیت شده پس دیتایی که برام کش کردی و دارم نشون میدم قدیمیه، لطفا برو و دوباره دیتای جدید رو فچ کن تا دیتای کش شده ام آپدیت بشه. اینجاس که اون query key بدرد میخوره. چون react query نمیدونه کدوم دیتارو باید اپدیت کنه و ما با پاس دادن این اسم به متد invalidateQueries میگیم که کدوم دیتارو باید اپدیت بکنه.درباره ی ٖqueryClient که از متد invalidateQueries اش استفاده کردیم جلوتر بیشتر توضیح میدم.حالا پراپرتی هایی که این هوک به ما برمیگردونه یکی فانکشن mutate هستش که ازش میتونیم برای آپدیت کردن دیتا و اجرای کل پروسه ای که الان توضیح دادم استفاده کنیم و پراپرتی بعدی isLoading هستش که تا وقتی که mutation هنوز انجام نشده( اپدیت صورت نگرفته و ریکوئست در حالت pending هست) این پراپرتی true خواهد بود تا ازش برای نشون دادن لودینگ استفاده کنیم.optimistic updatesپارامتر دوم هوک useMutation علاوه بر onSuccess متدای دیگه ای هم داره که یکیشون که خیلی کلیدی و جذابه onSettledوoptimisticUpdateهستش.فرض کنید وقتی میخواید یه آیتم به دیتاتون اضافه کنید(بفرستید سمت سرور) شما مطمعنید که دیتا به سرور با موفقیت فرستاده میشه یا به هر دلیلی دوس ندارید وقتی ایتم رو ادد میکنید منتظر جواب سرور بمونید و لودینگ ببینید. پس میاید به محض زدن دکمه ی اضافه کردن آیتم،‌اون آیتم رو دستی به دیتای کش شدتون اضافه میکنید و کاربر درجا با سرعت نور و بدون هیچ معطلی و لودینگی دیتای جدید رو میبینه:متد uptimisticUpate به محض اینکه ریکوئست زده بشه اجرا میشه و منتظر جواب نهایی ریکوئست نمیمونه، توی مثال بالا هم ما اومدیم به محض ریکوئست، با استفاده از متد setQueryData به React Query گفتیم که بیا و دیتایی که با اسم todos کش کردی رو اپدیت کن و این اسم todos رو به عنوان پارامتر اول دادیم و پارامتر دوم یه کال بک هست که دیتای کش شده ی فعلی رو به عنوان آرگیومنت میگیره و یه دیتای جدید برمیگردونه که آرایه ای شامل از دیتای کش شده ی فعلی به اضافه ی آیتم ادد شده ی جدید هستش. لازم به ذکره که ما ایدی هارو در این پروسه به صورت دستی و فی البداهه و موقت میدیم ولی وقتی ریکوست کامل شه دوباره دیتای کش شده تغییر میکنه و دیتایی که توی این متد اضافه کردیم پاک میشه تا دیتای اپدیت شده با ایدی های واقعی اضافه شن.حالا مشکلی که وجود داره اینه که اگه به هر دلیلی سرور ارور بده و نتونیم دیتای کش شده رو اپدیت کنیم همچنان قراره دیتای الکی که توی uptimisticUpdate اضافه کردیم توی کش باقی بمونه در حالی که ما واقعا همچون دیتایی نداریم و به صورت موقت میخواستیم نشونش بدیم تا دیتای اصلی با ایدی واقعی برسه.اینجاس که متد کلیدی بعدی به دادمون میرسه که بهش اشاره کردم onSettled، این متد بعد از اینکه سرور ریسپانس رو برگردوند بدون در نظر گرفتن ارور یا موفقیت صدا زده میشه و ما میتونیم توش بگیم که اگه سرور ارور برگردونده پس اون دیتای فیکی که توی uptimisticUpdate اضافه کردم رو حذف کن تا همون دیتای اصلی بمونه:متد onSettled چند تا ارگیومنت داره که ما فقط به error و context نیاز داریم از ارور برای این استفاده میکنیم که چک کنیم اگه ترو بود و ارور برگردونده بود دیتای فیک رو پاک کنیم پس دوباره با همون متد setQueries میایم دیتای کش شده رو میگیریم و فیلترش میکنیم که بیاد فقط ایتمایی که ایدیش با ایدی آیتم فیک ما یکی نیست رو نگه داره که همون دیتای کش شده ی اصلی بود و دیتای کش شدمون رو اینطوری برمیگردونیم به حالت قبل.همچنین توی ریکوئستمون داریم چک میکنیم که اگه response.ok فالس بود یه ارور برگردونه که باعث صدا زده شدن onSettled موقع ارور گرفتن بشه و همینطور توی uptimisticUpdate آیدی آیتم فیکمون رو برمیگردونیم که مقدارشو با عنوان  context به عنوان آرگیومنت onSettled میگیریم و جهت فیلتر کردن دیتا استفادش میکنیم.به کل این پروسه optimistic update گفته میشه که از قابلیت های کلیدی این لایبرری هستش.useQueryClientاین بزرگوار رو که تو مثال های بالا استفاده کردیم برای دسترسی به query client استفاده میشه که مسئول مدیریت کش و تغییر دیتای کش شده و invalidate کردنشون هست.مهم ترین متد هایی که این هوک بهمون میده :متدsetQueryData:  این متد دیتای کش شده ی query keyای که بهش میدیم رو آپدیت میکنه.متدgetQueryData: این متد دیتای کش شده ی query keyای که بهش میدیم رو بهمون میده.متدinvalidateQueries: این متد دیتای کش شده ی query keyای که بهش میدیم رو با Refetch یا همون ریکوئست مجدد از سرور آپدیت میکنه.Caching optionsما وقتی از useQuery تو مثال اولمون برای گرفتن دیتا استفاده کردیم فقط درباره دو پارامتر اولش حرف زدیم که شامل query key و ریکوئستمون بود حالا یه پارامتر سوم هم داریم که باهاش میتونیم قابلیت های کش کردن و ریکوئست زدنش رو کانفیگ و مدیریت کنیم مهم ترین پراپرتی ها برای کانفیگ کردن این موارد هستند:پراپرتی staleTime: با این پراپرتی میگیم که دیتایی که کش کرده چقدر تو حالت  stale بمونه قبل از اینکه Refetch بشه و این پراپرتی مقدار عدد رو به عنوان میلی ثانیه زمان میپذیره.پراپرتی cacheTime: با این پراپرتی میگیم که دیتا چه مدت میتونه تو حالت کش بمونه و بعدش اتوماتیک از حافظه کش پاک میشه که بهمون کمک میکنه بتونیم سایز کشمون رو مدیریت کنیم و نزاریم زیادی بزرگ شه و این پراپرتی مقدار عدد رو به عنوان میلی ثانیه زمان میپذیره.پراپرتی refetchOnMount: با این پراپرتی میگیم که کوئری باید موقع mount شدن کامپوننت دیتای خودش رو refetch بکنه یا نه و این پراپرتی مقدار boolean میپذیره.پراپرتی refetchOnWindowFocus: با این پراپرتی میگیم که کوئری باید موقعی که صفحه فوکوس میشه دیتای خودش رو refetch بکنه یا نه که بهمون کمک میکنه وقتی کاربر چند تا صفحه از اپلیکیشنمون رو همزمان باز کرده با جابه جا شدن بین صفحات صفحات دیگه دیتاشون قدیمی نمونه و اتوماتیک اپدیت بشه تا کاربر نیازی به رفرش صفحه نداشته باشه و این پراپرتی مقدار boolean میپذیره.پراپرتی refetchInterval: با این پراپرتی میگیم که کوئری باید هر چند ثانیه یبار ریکوئست بزنه و دیتارو اتوماتیک آپدیت بکنه  و این پراپرتی مقدار عدد رو به عنوان میلی ثانیه زمان میپذیره.پراپرتی retry: با این پراپرتی میگیم که کوئری باید موقعی که از سرور ارور میگیره چند بار دیگه مجدد ریکوئست بزنه و تلاش کنه که بهمون کمک میکنه ارور های سرور رو خیلی بهتر مدیریت کنیم و  تا حد ممکن اپلیکیشنمون رو ریسپانسیو نگه داریم و این پراپرتی مقدار عدد به عنوان تعداد دفعات تلاش مجدد میپذیره.پراپرتی retryDelay: با این پراپرتی میگیم که اگه داریم از پراپرتی retry استفاده میکنیم، کوئری هر چند ثانیه یبار باید تلاش مجدد رو انجام بده که بهمون کمک میکنه تا پدر سرور رو با تلاش های پشت هم در نیاریم و یه فاصله ای برای نفس کشیدن به سرور بدیم.پراپرتی staleWhileRevalidate:‌ با این پراپرتی میگیم که زمانی که داری دیتای کش شده رو به کاربر نشون میدی تو پشت صحنه دیتای جدید رو از سرور بگیر و دیتای کش شده رو باهاش اپدیت کن و این پراپرتی مقدار boolean میپذیره.با استفاده از این کانفیگ پراپرتی ها ما میتونیم استراتژی های مختلفی برای سیستم کش کردن اپلیکیشنمون داشته باشیم که من دو تا از استراتژی هارو اینجا توضیح میدم که شما میتونید یا از اینا استفاده کنید یا استراتژی خودتون رو بسته به نیاز پروژتون بسازید:استراتژی  stale-while-revalidate:با این استراتژی ما به کاربر دیتای کش شده (stale) رو نمایش میدیم در حالی که تو پشت صحنه دیتای جدید رو میگیریم و باهاش دیتای کش شده رو آپدیت میکنیم. این استراتژی بهمون کمک میکنه که تعداد دفعاتی که کاربر منتظر دیتا میمونه و به لودینگ زل میزنه رو کاهش بدیم و وقتی دیتایی رو بخواد به صورت آنی میتونه دیتای آماده رو ببینه:stale-while-revalidateاستراتژی network-first :با این استراتژی ما به فچ کردن دیتای تازه از نتورک اولویت بالاتری نسبت به دیتای کش شده میدیم و توی شرایطی استفاده ازش مناسبه که بخوایم مطمعن شیم که دیتایی که یوزر میبینه همیشه تازه ی تازه اس حتی اگه به قیمت فدا کردن یکم پرفورمنس بشه:network-firstتوی این مثال با ست کردن cacheTime و staleTime رو یک دقیقه داریم میگیم که هر یک دقیقه دیتای کش رو بپاک و دیتای جدید رو Refetch کن و با ست کردن refetchOnMount به false داریم میگیم که حتی موقع mount شدن هم سر خود فچ نکن دیتارو و هر یه دیقه اینکارو انجام بده و دیتارو تازه کن و با ست کردن retry به ۳ بهش میفهمونیم که اگه به ارور خورد تا سه بار تلاش مجدد انجام بده.نکته: اگه یک دیقه تموم بشه و دیتای جدید رو با سه بار تلاش نتونه از سرور بگیره میره کش رو نگاه میکنه و در صورتی که دیتایی موجود بود نمایش میده و در غیر اینصورت ارور نمایش میده.آیا از React Query میشه برای Global State Management استفاده کرد و بیخیال ریداکس و.. شد؟اگه میخوایم جواب این سوال رو بدونیم بهتره اول یه مفهومی رو بلد باشیم:Client State و Server Stateاستیت هایی که سمت کلاینت (مثلا مرورگر کاربر) مدیریت میشند و تغییرشون وابسته به عمل کاربر در خود اپلیکیشن هست و تغییرشون نیازی به ارسال ریکوئست نداره، Client State هستند. مثل: وضعیت لاگین کاربر، تمی که برای سایت انتخاب کرده، زبانی که برای سایت انتخاب کرده، دیتای داخل اینپوت های فرم که هنوز سابمیت نشدن.استیت هایی که سمت سرور ( بک اند) مدیریت میشند و تغییر توی دیتای این استیت ها نیاز به ارسال نتورک ریکوئست داره،  Server state هستند. مثل: لیست محصولاتی که برای خرید در یک فروشگاه در دسترس هستند، لیست مقاله هایی که در سایت ویرگول منتشر میشه، لیست آگهی های توی دیوار و...حالا برگردیم به جواب سوال اصلیمون:لایبرری react query به طور خاص و با هدف اصلی مدیریت ریکوئست ها و کش کردن دیتا به وجود اومده. اگر چه ما امکان استفاده ازش به عنوان global state management رو داریم ولی این لایبرری برای مدیریت ریکوئست ها و کش کردن دیتا ساخته شده و اگر چه با توجه به توضیحاتی که درباره استیت ها دادم بتونیم ازش برای مدیریت server states استفاده بکنیم اما نمیشه ازش استفاده مفیدی در client states کرد.البته میتونیم از این لایبرری برای مدیریت server states استفاده کنیم و برای client states از ریداکس یا context و.. استفاده کنیم اما باعث پیچیدگی بیشتر میشه.نظر شخصی خودم اینه که بهترین گزینه redux toolkit هستش که اگه مقاله ای که دربارش گذاشتم رو مطالعه کرده باشید(بخش  redux query)، متوجه میشید که اکثر قابلیت هایی که react query برای مدیریت ریکوئست ها و کش کردن دیتا داره رو ریداکس تولکیت هم داره به علاوه اینکه همه ی استیت ها هم هندل میکنه.ولی با اینحال با توجه به پروژه ای که دارید خودتون میتونید تصمیم بگیرید که دوس دارید از کدوم پکیج استفاده کنید و من فقط میخواستم با این لایبرری خفن که حرف زیادی برای گفتن داره آشناتون کنم. امیدوارم مفید واقع بوده باشه.خدانگهدار و موفق باشی ?</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Sat, 22 Apr 2023 17:21:14 +0330</pubDate>
            </item>
                    <item>
                <title>یادگیری Redux-toolkit، حتی ساده تر از ریداکس!</title>
                <link>https://virgool.io/@samAghapour/redux-toolkit-sam-aghapour-en9vcvop6anc</link>
                <description>Redux Toolkitتوی مقاله  &quot; یادگیری redux، ساده تر از چیزی که فکرش رو میکنی! &quot; ما درباره ریداکس صحبت کردیم و باهم یاد گرفتیم که چطور میتونیم ازش استفاده کنیم، اما همونطور که تو مقاله دیدیم و احتمالا موقع استفاده از ریداکس به ذهنتون خطور کرده اینه که کانفیگ کردن ریداکس پیچیده اس و از یه طرف خیلی تکرار واضحات نیاز داره و از طرف دیگه هم به خودی خود هیچ کار مفید و خاصی انجام نمیده و ما مجبوریم پکیجایی مثل redux-thunk, redux-persist , redux-saga و... نصب کنیم تا بتونیم ازش استفاده کنیم.حالا redux-toolkit اومده که همه ی اینارو یکجا به ما بده و کار رو راحت تر کنه، ئس بهتره به این نکته دقت کنید که redux-toolkit در واقع یه راه برای ساده تر نوشتن ریداکسه و در پشت پرده داره دقیقا همون کارایی که با ریداکس میکردیم رو انجام میده منتها ما دیگه نیازی نیست با خیلی از این پیچیدگی هایی که ریداکس داشت سر و کله بزنیم.ما قراره توی این مقاله یه استراکچر برای استفاده از متد های پر استفاده ریداکس تولکیت پیاده کنیم و بتونیم اکشن های async و sync بنویسیم و یه استراکچر کاملا متفاوت هم قراره داشته باشیم که توش قراره از rtk query استفاده کنیم که در واقع یه روش پیاده سازی ریداکس تولکیت هستش منتها این روش به ما توی فچ کردن و کش کردن دیتا هم کمک شایانی میکنه.نکته: اگه اولین باره کلا میخواید ریداکس یاد بگیرید و استفاده کنید توصیه میکنم قبلش یه سر به مقاله ریداکس بزنید تا کلا با چراییِ استفاده ازش و نحوه استفاده ازش رو بدونید چون ما توی این مقاله قرار نیست بگیم چرا داریم از ریداکس استفاده میکنیم و برای چه کاری خوب هستش.نکته: این مقاله رو بر این فرض نوشتم که شما هیچی از ریداکس نمیدونید و اولین باره میخواید وارد دنیای ریداکس شید و ترجیحتون ریداکس تولکیت هستش اما در عین حال یک سری نکات با عنوان &quot;نکته ریداکسی&quot; در طول مقاله گذاشتم که مخصوصِ کساییه که مقاله ریداکس رو خوندن و از قبل با ریداکس آشنا هستن، پس اگه با ریداکس هیچ آشنایی ندارید از خوندن نکات ریداکسی پرهیز کنید تا باعث گیج شدنتون نشه!1. نصب مواردلازمnpm install @reduxjs/toolkit react-reduxاین پکیج شامل همه ی چیزایی که ما نیاز داریم هستش از جمله redux-thunk , rtk query و... از react-redux برای ارتباط گرفتن ری اکت و ریداکس استفاده میشه برای مثال تغییر دادن دیتای توی store و یا خوندن دیتای مربوطه از استیت گلوبال.2. ساخت پوشه features در src پروژهمحتویات پوشه ی featuresبعد از ساخت پوشه features، ما برای هر اکشنمون یه پوشه میسازیم. مثلا توی عکس بالا ما یه پوشه ساختیم برای رد و بدل کردن محصولاتمون در استیت گلوبال و یه پوشه برای کتگوری هامون و یه پوشه برای کارت (سبد خرید) و...محتویات هر پوشه:محتویات پوشه cartهر پوشه شامل دو فایل بالا خواهد بود و تنها تفاوتشون اسم فایل دوم خواهد بود که مثلا عکس بالا چون محتویات پوشه cart هستش پس اسم فایلِ slice ( فایل دومی) برابر با cartSlice هستش.نکته ریداکسی: slice دقیقا مثل ردیوسر خواهد بود همونطور که توی ریداکس اسم فایل ردیوسر برابر با xxxReducer میبود اینجا هم به همین صورت xxxSlice خواهد بود و ما نیازی به فایل ردیوسر برای هر اکشن نخواهیم داشتفایل action شامل تمام اکشن ها(فانکشن ها) یی خواهد بود که میخوایم ازشون استفاده کنیم تا دیتایی رو رد و بدل کنیم مثلا فایل action پوشه cart :اکشن های فایلaction برای cartما از createAsyncThunk برای ساخت اکشن های async استفاده میکنیم که اولین ورودی که میگیره در واقع یه استرینگ هستش که تایپ این اکشنمون به حساب میاد و مقدار دوم یه کال بک هستش که همون فانکشن async مون هستش که باید جاهای دیگه با اسمی که برای متغیر نوشتیم صداش کنیم برای مثال اولین اکشن عکس بالا getCart خواهد بود و با همین اسم اون کال بک رو صدا خواهیم زد و اگه نیازه که ارگیومنتی به این اکشنمون پاس بدیم در صورتی که فقط یدونه ارگیومنت نیاز داشت به صورت تکی مینویسیمش مثل اکشن deleteFromCart توی عکس بالا که فقط یدونه id رو نیاز داره ، اما اگه اکشنمون به چند تا ارگیومنت نیاز داره باید به صورت ابجکت بگیریمش مثل اکشن addToCart یا updateCart توی عکس بالا.حالا ما داخل این کال بک بصورت async/await ریکوئستمون رو میزنیم( حالا چه با axios چه با fetch چه با هر چیزی) و دیتایی که میگیریم رو ریترن میکنیم در واقع چیزی که این کال بک قراره برای slice به طور خودکار بفرسته شامل یه ابجکت خواهد بود که پراپرتی به اسم payload خواهد داشت که همون دیتاییه که داریم از سرور میگیریم و ریترن میکنیمنکته ریداکسی: همونطور که متوجه شدید ما با متد createAsyncThunk نیازی به استفاده از redux thunk نخواهیم داشت و ریداکس خودش پشت پرده هندل میکنه قضیه رو و همینطور مقدار اولی که createAsyncThunk گرفت رو همون type ای در نظر بگیرید که توی ریداکس با اکشن هامون میفرستادیم و باید هر تایپ منحصر به فرد میبود.خب حالا بعد از نوشتن اکشن هامون نیاز به یک slice خواهیم داشت تا روی این اکشن ها نظارت کنه و یه جورایی بعد از صدا شدن اکشن هامون مقدار ریترن شده رو( payload) رو بگیره و بفرسته تو استیت گلوبال.پس یه فایل cartSlice برای مثال بالا میسازیم که محتواش به این صورت خواهد بود:محتوای فایل cartSliceخب ما یه متد createSlice خواهیم داشت  که یه آبجکت میگیره و توش میتونیم آپشن های به خصوصی رو بنویسیم از جمله name که اسم slice ما خواهد بودنکته : اگر دقت کنید میتونید متوجه این قضیه بشید که اسمی که به slice مون میدیم همون اسمی هستش که ازش توی پارامتر اول createAsyncThunk قبل از اسلش &quot; / &quot; استفاده کردیم ولی بعد از &quot;/&quot; ، هر اکشن، تایپ به خصوص خودش رو خواهد داشت ما اینطوری داریم میگیم که slice ای به نام cart به این اکشن ها نظارت خواهد کرد و در کل خوبی این کار اینه که وقتی یکی از اکشن هارو صدا بزنیم اون slice ای که داره بهش نظارت میکنه قادر خواهد بود زمان pending و rejected و fulfilled اون اکشن رو داشته باشه و ازش بتونیم استفاده های مفیدی کنیمدومین آپشن، initialState خواهد بود که برابر با مقدار اولیه برای استیتمون هستش که توی عکس بالا یه آبجکت با پراپرتی value که به صورت دیفالت nullهستش داریم.نکته ریداکسی: دقیقا مثل توی reducer که ما یه مقدار initialState داشتیم اینجا هم به همون نیاز داریمسومین آپشن، extraReducers خواهد بود که برابر با یه فانکشن هستش که یک پارامتر به اسم builder میگیره و بیلدر یه متدب ه اسم addCase داره که ما ازش برای آپدیت کردن استیتمون در شرایط مختلف استفاده خواهیم کردمتد addCase دوتا پارامتر میگیره اولی وضعیتی هست که میخوایم و دومی یه کال بک هست که توش میایم وابسته به اون وضعیت یه بلایی سر initialState میاریم و این کال بک دوتا پارامتر میگیره اولی همون state اولیه ای هست که میخوایم اپدیتش کنیم و دومی action هستش که از اکشنمون ریترن شده و یه پراپرتی payloadداره که مساوی با دیتایی هستش که از سرور گرفته: مثلا توی مثال بالا ما هر چهار تا اکشن هامون رو ایمپورت کردیم و برای هر کدوم یه addCase نوشتیم توی اولین addCase گفتیم اگه اکشن getCart مخابره شد و  وضعیت fulfilled داشت بیا پراپرتی value داخل استیت رو به دیتایی که داره از این اکشن برمیگرده تغییر بده و همینطور پشت سرش دوباره سه تا .addCase دیگه نوشتیم برای اکشن های دیگه موناینم یه مثال دیگه از یه slice متفاوت برای یه اکشن دیگه که توش وضعیت های جذاب تری نوشتیم:توی مثال بالا ما یه پراپرتی error و loading هم داریم که میتونیم توی شرایطی که وضعیت اکشنمون pending یا rejected بود ازش استفاده کنیم تا برای مثال توی یو آی ازشون برای لودینگ یا نشون دادن ارور استفاده کنیم تا حس کاربری بهتری رو ایجاد کنیمنکته: توی ریداکس معمولی معمولا باید یه استیت گلوبال لودینگ یا یا استیت لیودینگ داخلی میداشتیم تا ازش برای نشون دادن لودینگ استفاده کنیم به صورتی که قبل از ریکوئست، لودینگ رو با مقدار true مخابره میکردیم و بعد از پایان ریکوئست همون لودینگ رو با مقدارfalse مخابره میکردیم، اما با ریداکس تولکیت کارمون خیلی راحت تر شده و نیازی به استیت اضافه ای مثل لودینگ و ارور نیستنکته مهم: آبجکت ها توی جاوااسکریپت immutable یا تغییر ناپذیر هستن و نمیتونیم همینطوری یه پراپرتیش رو برابر با یه دیتایی قرار بدیم و میومدیم بجاش به اینصورت استیت رو اپدیت میکردیم:return {...initialState , value: payload.action}به این صورت ما کل ابجکت قبلی رو کپی میکردیم و اون پراپرتی که میخواستیم تغییر بدیم رو برابر با مقدار جدید میذاشتیم( و عملا یه ابجکت جدید رو جاگذاری میکردیم به جای قبلی).این روش ممکنه یه مقدار رو مخ باشه و از همین جهت توی redux toolkit ما نیازی به رعایت این قانون نداریم و میتونیم خیلی راحت هر مقداری رو مساوی با مقدار جدید بزاریم که البته ما فقط توهم این رو خواهیم داشت که داریم اون ابجکتمون رو تغییر میدیم اما در پشت پرده ریداکس تولکیت از پکیجی به اسم immer استفاده میکنه تا بیاد چیزی که ما نوشتیم رو به همون روش کپی کردن قبلی بنویسهنکته: اگه توی وضعیت pending لودینگ رو مساوی با true یا هر مقداری قرار دادیم باید توی شرایط دیگه در صورتی که دیگه بهش نیاز نداریم مقدارشو به همون مقدار دیفالت برگردونیم مثل توی عکس بالا که توی شرایط ارور یا fulfilled، لودینگ رو false کردیم چون نباید true میموند و بهش نیازی نداشتیم.چهارمین آپشنمون، reducers خواهد بود که ازش برای نوشتن اکشن های sync استفاده میشه و حتی نیازی نیست توی یه فایل جدا اکشنارو بنویسیم، اپشن reducers در واقع یه ابجکته که توش فانکشن هامون رو مینویسیم که همون اکشن های sync ما هستن و مقدار اولی که میگیرن استیت هست که همون initialState خودمونه که میخوایم تغییرش بدیم و مقدار دوم که میگیرن action هستش که یه payload  داره که همون دیتایی میشه که ما موقع صدا کردن این اکشنمون بهش به عنوان پارامتر اول پاس میدیم مثال:وقتی اکشنی داخل reducers مینویسیم متد createSlice اون اکشن هارو برا ما برمیگردونه و طبق عکس بالا باید از پراپرتی modeSLice.actions به صورت دی استراکچر شده اکشن هارو بگیریم و اکسپورت کنیم تا بتونیم ازشون برای رد و بدل کردن دیتا استفاده کنیم.اگه دقت کرده باشید توی خط اخر فایل های xxxSlice ، ما یه reducer داریم از slice برمیگردونیم که در واقع به ما اجازه میده به صورت reducer توی استیت گلوبال اضافش کنیم3. ساخت فایل store در src پروژهمتغیر store همون استیت گلوبال ما خواهد بود که در نهایت هر اکشنی یه دیتایی رو مخابره کنه توی پراپرتی های همین استیت ذخیره میشند.برای ساخت این استیت گلوبال نیاز به configureStore داریم که یه ابجکت میگیره که توش میتونیم آپشن هایی بنویسیم از جمله reducer که یه ابجکت از ردیوسر هایی خواهد بود که توسط createSlice ساخته و اکسپورت میشننکته ریداکسی : با متد configureStore دیگه نیازی نیست از combineReducers و یا حتی کانفیگ reduxDevTool استفاده کنیم خود این متد اینارو اضافه میکنه.4. اضافه کردن store به provider در فایل index بعد از ایمپورت کردن store، با provider دور کامپوننت App که هفت جد و آباد همه ی کامپوننتای دیگس محاصره میکنیم و بهش پراپی میدیم که store رو دربر داره و حالا هر کامپوننتی داخل app.js هر چقدر هم تو در تو باشه میتونه به صورت مستقیم به هر دیتایی دسترسی داشته باشه بدون اینکه از بالا تا پایین یکی یکی فلان دیتا رو بهش پاس بدیم که در ادامه میگم چطور.5. استفاده از اکشن ها و استفاده از ردیوسر هاما یا میخوایم یه اکشن رو بفرستیم تا دیتا رو تغییر بده و یا میخوایم دیتایی که تغییر کرده رو از ردیوسر بگیریم و توی یو ای نمایش بدیم. مخابره یا ارسال کردن دیتا برای تغییر استیت(dispatch):اگه اکشن addToCart رو توی مثالای بالا یادتون باشه ما اینجا اومدیم ایمپورتش کردیم و همینطور یه هوک به اسم useDispatch از react redux ایمپورت کردیم که به شکل بالا میتونیم ازش استفاده کنیم تا اکشنی که داشتیم رو مخابره کنیم و نکته ی دیگه اینکه اکشنمون دوتا پارامتر id و quantityNumber میگرفت که باید توی ابجکت میذاشتیمش پس اینجا دوتا پارامتر رو داخل ابجکت به اینصورت که میبینید پاس میدیم.. خوندن دیتا از استیت گلوبالی که داریم:ما هوکی به اسم useSelector رو از rect-redux ایمپورت میکنیم و این هوک یه کال بک میگیره که این کال بک یه پارامتر استیت داره که همون آبجکت استیت گلوبالِ ما توی store هستش و میتونیم از پراپرتی های مختلفی که هر کدوم برابر با یکی از ردیوسر ها بودن استفاده کنیم و توی مثال بالا ما داریم ازدیتای cart توی هدر استفاده میکنیم که یه پراپرتی value داشت پس ما هر سری که اون addToCart رو مخابره کنیم اون slice میاد و در صورت fulfilled بودن (همونطور که نوشتیم) مقدار value ی داخل cart رو با دیتایی که از اکشنمون گرفته اپدیت میکنه. اگه کارت علاوه بر value پراپرتی های دیگه ای مثل error , loading داشت هم میتونستیم ازشون به صورت شرط استفاده کنیم و یو آی بهتری داشته باشیم.RTK Queryاگه به دنبال استراکچر متفاوتی هستید که توی data fetching و data caching (کش کردن دیتا و ممانعت از ریکوئست های غیر ضروری) هم بهتون کمک کنه این قسمت مخصوص شماس.اولین کاری که باید بکنید اینه که بیخیال استراکچری که تا الان دربارش حرف زدیم بشید و به صورت زیر کانفیگ ریداکس رو انجام بدید.1. ساخت پوشه services در src پروژهپوشه services شامل یه فایل هستش به اسم xxxApi شما میتونید هر چیزی به جای xxx بزارید ( توی مثال ما اسمشو میزاریم onlineShopApi)محتوای این فایل به این صورته:ما با createApi میتونیم از اندپوینت هایی که داریم برای ریکوئست های مختلف استفاده کنیم و یه data fetching تر تمیز در بیاریم ازش. متد createApi یه ابجکت از آپشن ها میگیره که شامل مهمتریناش که توی عکس هم میبینید شامل موارد زیر هستش:آپشن reducerPath : این آپشن در واقع یه کلید برای سرویس api شما خواهد بود که ازش توی استیت گلوبال جلوتر قراره استفاده کنیم و این اسم باید منحصر به فرد باشه.آپشن baseQuery :  مقدارش مساوی با fetchBaseQuery هستش که از ریداکس تولکیت ایمپورتش میکنیم، fetchBaseQuery یه wrapper دورِ fetch هستش که صرفا ریکوئست هارو ساده تر میکنه و یه آبجکت به عنوان ورودی میگیره که میتونیم توش نیازداریم رو قرار بدیم مثلا ما توی ریکوئست هامون یه baseUrl داریم که ثابته و یه سری اندپوینت داریم که متنوعه و آپشن baseUrl برای مشخص کردنِ baseUrl هستش.آپشن endpoints : مقدارش مساوی با یه فانکشن هستش که یه پارامتر build میگیره و این فانکشن یه ابجکت برمیگردونه که شامل همه ی ریکوئست های ما با اندپوینت های مختلف هستش هر ریکوئست مساوی با builder.query یا builder.mutation هست که یه فانکشن هستن و یه ابجکت میگیرن:اگه ریکوئستمون متد get هستش با builder.query مینویسیمش که داخل ابجکتی که میگیره یه فانکشن query قرار میدیم که اندپوینتِ اون ریکوئستمون رو برمیگردونه(مثل getProductDetails یا getCart توی مثال بالا) اگه نیاز به ایدی یا دیتا توی ریکوئستمون داشته باشیم باید به عنوان پارامتر query دریافتش کنیم.اگه ریکوئستمون متد هایی برای آپدیت کردن دیتا هستند مثل post , patch , put , delete ، با builder.mutation مینویسیمش که داخل ابجکتی که میگیره یه فانکشن query قرار میدیم که url ( اندپوینت ) و method  و در صورت نیاز body رو برمیگردونه ( مثل addToCart  و deleteFromCart توی مثال بالا) طبق معمولاگه به ایدی یا دیتای body نیاز داشتیم میتونیم به صورت پارامتر query دریافتش کنیم.حالا createApi با توجه به این آپشن هایی که دادیم برای هر اندپوینتمون یه هوک میسازه و برمیگردونه و ما میتونیم با دی استراکچر کردن بگیریمشون و اکسپورتشون کنیم تا هر جا که نیاز بود با این هوک ها ریکوئست هامون رو بزنیم و این هوک ها به این شکل اسم گذاری میشن(مثل توی مثال بالا خط آخر):برای builder.query ها :use + اسم اندپوینت شما + Query = مثلا useGetCartQuery()برای builder.mutation ها:use + اسم اندپوینت شما + Mutation = مثلا useDeleteFromCartMutation() علاوه بر این هوک ها، createApi برامون یه ردیوسر هم میده که ازش توی استیت گلوبالمون استفاده کنیم که توی قدم دوم قراره اینکارو کنیم.2. ساخت فایل store در src پروژههمونطور که حدس میزنید ما فایل store رو میزنیم تا استیت گلوبالمون رو توش کانفیگ کنیم در صورتی که از استراکچر rtk query استفاده کنیم باید محتوی این فایل به این صورت باشه:میبینیم که برای اسم ردیوسری که از api میگیریم از آپشن reducerPath استفاده میکنیم و اینجا بدردمون خورد.تفاوت چشمگیری که این کانفیگ با کانفیگ قبلی داشت اینه که ما اینجا جز ردیوسر یه اپشن دیگه هم به configureStore اضافه کردیم به اسم middleware. به صورت دیفالت وقتی این آپشن رو اضافه نکنیم یه سری middleware به استور اضافه میشن و ما با قرار دادن این اپشن میتونیم بگیم که چه middleware هایی اضافه شن و در نتیجه باید ارایه ای از middleware ها داشته باشیم برای این اپشن. توی عکس بالا ما با کمک getDefaultMiddleware گفتیم که بیا همه ی middleware های دیفالتی که همیشه اضافه میکنی رو به اضافه middleware هایی که از onlineShopApi میان رو با هم به استور اضافه کنبرای مثال یکی از middleware های دیفالتی که همیشه ادد میشه thunk هستش که باعث ارتباط گرفتن ریداکس با اکشن های async میشهنکته ریداکسی: هر middleware ای که توی لیست middleware ها قرار میدیم در واقع قراره توسط applyMiddleware که توی ریداکس هم داشتیم به استور اضافه بشن.نکته: middleware هایی که از api میگیریم و به middleware های دیفالت اضافه میکنیم در واقع در جهت کمک به کش کردن دیتا و ولیدیشن و... ازشون استفاده میشه.3. اضافه کردن store به provider در فایل index این مرحله دقیقا مثل مرحله 4 روش قبلی هستش و هیچ تفاوتی نداره.4. استفاده از هوک های mutation و queryما یا میخوایم به وسیله ی هوک های query ریکوئست بزنیم و دیتایی رو get کنیم و یا میخوایم به وسیله ی هوک های mutation ریکوئست بزنیم و دیتایی رو بفرستیم.. گرفتن دیتا به وسیله ی هوک های query :طبق مثال بالا، هوک های query به ما پراپرتی هایی مثل isLoading و data و isError رو برمیگردونن و ما دیگه نیازی نداریم توی استیت گلوبال با چیزایی مثل loading و error  نوشتن سر و کله بزنیم به محض mount شدن کامپوننت ریکوئست زده میشه و دیتا رو میگیره و از دفعات بعد اون دیتا cache میشه و دیگه لودینگ نخواهیم داشت ( لودینگ فقط اولین بار که دیتا خالیه و کش نشده نشون داده میشه) و بجاش دیتای از قبل کش شده رو نشون میده.. پست کردن، ادیت کردن، حذف کردن دیتا به وسیله ی هوک های mutation:طبق مثال بالا، هوک های mutation یه فانکشن بهمون برمیگردونن که میتونیم صدا بکنیمش و پارامتر هایی که میخواست رو به صورت ابجکت بهش پاس بدیم( اگه یه پارامتر میخواد میتونین داخل ابجکت نزارینش) و این هوک علاوه بر فانکشن، یه ابجکت هم برمیگردونه که نتایج ریکوئستمون رو برامون میفرسته این ابجکت نتایج شامل پراپرتی هایی از جمله isLoading و isError و data و... هستش که ازشون میتونیم توی یو آی استفاده کنیم.این دومین روشی بود که میشه از ریداکس استفاده کرد و چیزی که باید بهش توجه کرد اینه که چه توی روش اول چه توی روش دوم برای هر متد کلی آپشن و کلی راه مختلف پیاده سازی و کلی متد و تکنیک دیگه وجود داره که مسلما نمیشه همشون رو توی مقاله گنجوند.توی این مقاله سعی کردم که ساده ترین روش پیاده سازی رو با چند تا از مهم ترین و پر کاربردترین متد هارو براتون توضیح بدم تا برای شروع بتونید ازش استفاده بکنید اما اگه خیلی به ریداکس تولکیت علاقه مند شدید میتونید به داکیومنت رسمیش سر بزنید و دانشتون رو در این زمینه با یادگیری مابقی متد ها و آپشن ها کامل کنید.خدانگهدار و موفق باشی ?</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Sun, 31 Jul 2022 03:14:30 +0430</pubDate>
            </item>
                    <item>
                <title>نکاتی برای بهبود پرفورمنس در پروژه های React</title>
                <link>https://virgool.io/@samAghapour/performance-tips-for-react-projects-sam-aghapour-hfkxygunomtl</link>
                <description>توی این مقاله قراره کلی نکات که برای بهتر کردن تجربه کاربری و بالا تر بردن پرفورمنس توی پروژه های ری اکتی لازمه رو یاد بگیریمبا خوندن این مقاله هم با یه بخش دیگه از هوک های کاربردی ری اکت آشنا میشید تا کلا پرونده هوک ها که تو قسمت اول بخشی ازش رو شروع کردیم بسته شه، هم بعضی قابلیتای ورژن جدید ری اکت رو یاد میگیرید تا  آپدیت شید، هم کلی نکات پرفورمنسی یاد میگیرید.1. useTransition()این یکی از باحال ترین هوک هاییه که توی ورژن جدید معرفی شده و واقعا کاربردیه!اگه بخوام خیلی ساده توضیحش بدم با یه مثال شروع میکنم:فرض کنید یک لیست هزارتایی از محصولاتتون دارید که توی یه صفحه نمایششون میدین، و یه اینپوت سرچ دارید که با سرچ کردن اسم محصول، اون هزارتا محصول رو فیلتر میکنید ، با وارد کردن هر حرفی توی اینپوت اون پروسه ی فیلتر کردن هزارتا محصول دوباره از سر گرفته میشه تا دیتا رو بر اساس اون اسم سرچ شده آپدیت کنه، حالا مشکلی که بهش برمیخوریم اینه که چون این پروسه ی فیلتر کردن سنگینه اگه شما بخواید سه چهارتا کلمه رو پشت سر هم بنویسید متوجه یه تاخیر سنگین تو وارد شدن اون حروف به اینپوت و یه لگ خیلی سنگین میشید(هرچی دیتا بزرگ تر، لگ سنگین تر).اگه تا حالا همچین چیزی رو تجربه نکردین حتما به دمویی(لینک دمو) که برای مثالمون آماده کردم یه سر بزنید و سعی کنید مثلا 4444 رو سرچ کنید تا محصولات فیلتر شن و بعدش 4444 رو یکجا پاک کنید تا متوجه لگ یا تاخیر در پاک شدن که دربارش حرف میزدم بشیدتوی ری اکت این پروسه به این شکل هستش: ما یه استیت داریم که مقدار اینپوت رو داخلش ست میکنیم (با وارد کردن هر حرف این استیت اپدیت میشه و عملا مقدار داخل اینئوت هم آپدیت میشه) و یه استیت داریم که اون هزار تا محصولاتمون داخلشه و برای اینپوت یه هندلر () میزاریم که با وارد کردن حروف اون دیتا رو فیلتر کنه و استیت محصولاتمون رو آپدیت کنه :حالا دلیل پشت پرده ی این لگ یا تاخیر چیه که باهاش مواجه شدیم:ری اکت همه ی استیت هارو سعی میکنه به یکباره اپدیت و کامپوننت رو رندر بکنه، ینی میاد همه ی استیت هارو اپدیت میکنه اما استیت کوئری زودتر اپدیت میشه چون پروسه پیچیده و خاصی نداره اما با اینکه آپدیت شده ری اکت نمیفرستتش تو صفحه تا فعلا پروسه آپدیت شدن استیت محصولات هم تموم شه و بعد که تموم شد تازه جفتشو باهم ری رندر و پینت میکنه رو اسکرین و با این تفاسیر همه ی استیت ها برای آپدیت شدن از یه درجه اولویت بهره مندند(همه ی استیت ها در ری اکت بالاترین اولویت را دارند) و ری اکت پارتی بازی قائل نمیشه! و در نتیجه یکبار صفحه رو ری رندر میکنه که همه ی استیت های اپدیت شده توش باشن.نکته: برای حل این مشکل لگ زدن و تاخیر ما توی ورژن های قبلی از روش هایی مثل پجینیشن (pagination)و... استفاده میکنیم تا دیتارو محدود کنیم تا در نتیجه موقع سرچ و فیلتر کردن فقط تعداد خاصی که توی صفحه اول نشون میدیم رو فیلتر کنه و خیلی سنگین نشه پروسه اش.Concurrent renderingحالا توی ورژن جدید ری اکت، این پارتی بازی با استفاده از هوک &quot;useTransition&quot; ممکن شده و شما میتونید در کنار پچینیشن با این هوک یه زیرمیزی هم به ری اکت بدین تا دیرتر بره سراغ فلان استیت و اول کار بقیه استیت هارو راه بندازه. ینی چی؟ما میخوایم استیت هایی مثل استیت کوئری برای اینپوت که اصلا نیازی به زمان و پروسه خاص ندارن خیلی سریع آپدیت بشن و برن تو اسکرین تا مجبور نباشن منتظر آپدیت شدن بقیه استیت ها بمونن و استیت هایی مثل فیلتر کردن محصولات که خیلی زمان میبرن اولویت پایینتری داشته باشن در نتیجه این کار باعث میشه ری اکت چند بار ری رندر بکنه کامپوننت رو (یکبار برای استیت هایی که در اولویت بالا هستند اپدیت و ری رندر میشه تا فعلا کار اونا راه بیفته و در عین حال از اونور داره همزمان پروسه ی کم اولویت هارو پیش میبره تا بعد از اتمام پروسه با یه ری رندر دیگه اونارو هم بفرسته تو صفحه) به این قابلیت چند رندری همزمان که توی تازه ترین ورژن ری اکت اضافه شده، concurrent rendering میگویند.توی مثال دنیای واقعی مثل این میمونه که من امروز باید این مقاله رو بنویسم و در عین حال باید غذا هم بخورم پس آیا درسته که مقالمو با اینکه نوشتم تموم شده ولی منتشرش نکنم تا غذام بپزه و بعد تازه شروع کنم به خوردن و بعد از تموم کردن غذام دکمه انتشار رو بزنم که جفتش هم زمان تموم شده باشه؟! نه خب من با ویژگی concurrent میتونم مقالم رو بنویسم و در عین حال غذا که اولویت پایینتری داره رو بزارم بپزه و من مقالم به محض تموم شدن منتشر میکنم و و بعدش غذام هم که هر وقت آماده شد میخورمش. منطقی بنظر میرسه مگه نه؟ اینطوری کلی &quot; سریع تر &quot; کارام انجام میشه و تجربه بهتری بدست میارم.نکته: برای اینکه ری اکت بتونه از قابلیت  چند رندری همزمان استفاده کنه باید آخرین ورژن ری اکت استفاده بشه و method ReactDom به شیوه جدیدش نوشته شده باشه:حالا useTransition چطور استفاده میشه؟این هوک یه آرایه با دو مقدار برمیگردونه که اولیش isPending و دومیش StartTransition هستش:مقدار isPending برابر با true یا false هستش و تا زمانی که اون استیت اولویت پایین هنوز کامل آپدیت و رندر نشده این مقدار true هستش و ازش میتونیم برای لودینگ استفاده کنیم به این صورت که اگه isPending بود بجای محصولاتمون کلمه loading رو نشون بدیم و تجربه کاربری بهتری داره.مقدار startTransition یه فانکشن هست که یه کال بک میگیره که داخلش ست استیت هایی که اولویت پایین تری دارن رو قرار میدیم تا ری اکت متوجه بشه که این استیت ها اولویت پایین تری دارند و نباید بقیه رو بخاطر این استیت ها منتظر بزاره. به این صورت:حالا برید این نسخه دمو ( لینک دمو ) رو امتحان کنید تا ببینید چقدر خفن تر و بهتر شده دیگه خبری از لگ و تاخیر موقع یهویی پاک کردن اینپوت نیست و یه لودینگ هم داریم که وضعیت پروسه فیلترینگ رو به ما نشون میده:نکته: یادتون باشه فقط از useTransition برای همچین مواقعی استفاده کنید و سعی نکنید هر چیز بیخودی رو اولویت بندی کنید چون ری اکت با همزمان سازی ری رندر ها فشار خاصی رو محتمل میشه که ممکنه اون اولویت بندی شما ارزش این فشار رو نداشته باشه و در آخر نتیجه معکوس داشته باشه برای پرفورمنس!2. useDeferredValue()این هوک دقیقا مثل هوک useTransition هستش منتها فرقشون اینه که از useTransition وقتی استفاده میکنید که داخل کامپوننتمون به setState دسترسی داشته باشیم و اما مواقعی هست که ما استیت رو از کامپوننت پدر به صورت پراپ گرفتیم و به ست استیتِ اون پراپ دسترسی نداریم پس بجاش میایم از هوک useDeferredValue استفاده میکنیم که فقط یه مقدار قبول میکنه و اون مقدار چیزی نیست جز همون استیتی که میخوایم اولویت پایینی داشته باشه:این کد بالا در نتیجه هیچ فرقی با کد های بالاتر که که با استفاده از useTransition بود نداره و جفتشون کارشون رو به نحو احسنت انجام میدن البته در این حالت دیگه isPending رو نداریم.3. useMemo()تصور کنید یه کامپوننت داریم به این صورت:یه فانکشن greetingFunc داریم که پروسه حلقه ایِ سنگینی رو داره انجام میده و در نتیجه یه مقداری رو برمیگردونه حالا ما یه متغیر به اسم greeting داریم که میاد این فانکشن رو صدا میکنه و استیت اسم رو بهش پاس میده و اون پروسه انجام میشه و مقدار متغیرمون برابر میشه با مقدار خروجیِ اون فانکشنمون حالا یه تم هم داریم که از استیت دیگه ای داره یه شرطی اجرا میکنه که اگه ترو بود بیاد مشکی کنه استایلو.حالا اگه ما هر سری بخوایم این تم رو با زدن دکمه ی change theme عوض کنیم بخاطر آپدیت شدن استیت darkTheme ، کل کامپوننت ری رندر میشه و اون متغیر greeting دوباره اون فانکشن رو صدا میکنه و یه پروسه سنگین رو انجام میده و باعث محتمل شدن یه بار سنگین به پرفورمنس میشه. حالا چیزی که شاید متوجهش شده باشید اینه که این بار اضافی سرِ هیچی اضافه شده! وقتی ما داریم تم رو عوض میکنیم استیت اسم که داریم پاسش میدیم به فانکشن عوض نشده و در نتیجه فانکشن همون خروجی رو میده. پس وقتی همون خروجی رو میده و اسم همونه چرا باید این فانکشن از اول اجرا شه و اون پروسه سنگین تکرار شه؟اینجاس که useMemo میاد وسط و با استفاده ازش میتونیم این فانکشن رو به یاد بسپاریم و اگه اون دپندسی که ما بهش میدیم تغییری نکرده باشه این فانکشن دوباره اجرا نمیشه و همون خروجی قبلی رو میده(چون دپندسنی که اینجا استیت name باشه تغییری نکرده).هوک useMemo یه کال بک میگیره که توش فانکشنی که میخوایم به یاد سپرده بشه رو ریترن میکنه و به عنوان آرگومان دوم یه آرایه قبول میکنه که توش میتونیم دپندنسی هامون رو بزاریم تا فقط هروقت که این دپندسی ها تغییر کردن این فانکشن از دوباره اجرا بشه و اصلا با این قضیه که &quot;کامپوننت داره ری رندر میشه پس منم از دوباره فانکشن اجرا میکنم&quot; کاری نداره و فقط چشمش به دپندنسی هاس.مثال بالا رو با هوک useMemo به اینصورت مینویسیم:مثال بالا رو میتونید توی دمو ( لینک دمو ) امتحان کنید یکبار با هوک سعی کنید تم رو عوض کنید و یکبار بدون هوک useMemo تا ببینید متن &#x27;greetingFunc has been created again &#x27; با عوض شدن تم دوباره لاگ میشه یا نه.4. useCallback()ما به دو دلیل از useMemo و useCallback استفاده میکنیم:برابری ارجاعی یا Referential equalityمحاسبات پر هزینه یا Computationally expensive calculationsدر مورد مورد دوم حرف زدیم که چجوری با useMemo میتونیم از تکرار محاسبات سنگین جلوگیری کنیم( با به یاد سپردن خروجی اون محاسبات)هوک useCallback هم وظیفه هندل کردن مورد اول رو داره، بیاید با مثال جلو بریم:مثل چیزی که تو عکس بالا میبینید بعضی وقتا پیش میاد که ما یه فانکشن رو به عنوان پراپ پاس بدیم به کامپوننت فرزند تا ازش استفاده کنه حالا فکر کنید وقتی استیت رو توی کامپوننت پدر با دکمه increase آپدیت کنیم چه اتفاقی میفته؟ =&gt; فانکشن  که به عنوان پراپ پاس داده شده به کامپوننت dummyButton از نو ساخته میشه و وقتی از نو ساخته بشه حتی اگه شبیه قبلی هم باشه با قبلی یکی نیست! توی جاوااسکریپت وقتی یه فانکشن یا آبجکت میسازیم توی یه آدرسی ذخیره میشه و وقتی یه آبجکت دقیقا کپی همون ساخته شه با این که شکلاشون یکیه ولی با یه آدرس جدا ساخته شده که این قضیه پدیده ی Referential equality رو به وجود میاره. با ساخته شدن فانکشن  جدید چون پراپ تغییر کرده پس کامپوننت فرزند ( DummyButton) هم تغییر میکنه اینجاس که پای useCallback میاد وسط و ما کافیه فانکشنمون رو به عنوان کال بک پاس بدیم بهش و و به عنوان ارگومان دوم هم یه آرایه از دپندسی بدیم که هر وقت دپندسی تغییر کرد اون فانکشن رو دوباره بسازه و در غیر این صورت همون فانکشن رو با همون آدرس خودش به یاد میسپره و وقتی با همون آدرس به یاد سپرده شده باشه دیگه تغییری هم صورت نگرفته که باعث ری رندر شدن بیخودِ کامپوننت فرزند بشه و پرفورمنس خوشحال تره!مثال بالا، با استفاده از useCallback به صورت زیر نوشته میشه و شما میتونید با رفتن به دمو ( لینک دمو ) همین مثال رو یبار با هوک و یبار بدون هوک تست کنید تا ببینید وقتی استیت با دکمه increase تغییر میکنه آیا باعث ری رندر شدن dummyButton و لاگ شدن متن &#x27; dummy button component rerendered  &#x27; میشه یا نه.نکته: فرق useMemo و useCallback اینه که useMemo اون مقدار برگشتی از داخل فانکشن رو به یاد میسپره تا دوباره فانکشن اجرا نشه، ولی useCallback خود فانکشن رو به یاد میسپره تا دوباره فانکشن ساخته نشه.نکته : از این دو هوک فقط و فقط سعی کنید توی این دو شرایط برابری ارجاعی و محاسبات سنگین استفاده کنید و در غیر اینصورت اگه بخواید هر فانکشن کوچیکی که مینویسید رو memoize یا به یاد سپاری کنید ممکنه نتیجه معکوس بده و بخاطر یه محاسبه کوچیک بی ارزش ری اکت کلی درگیر اجرای useCallback و useMemo بشه و بدتر پرفورمنس رو درگیر و سنگین کنه.5. React.memo()وقتی توی کامپوننتمون یه سری کامپوننت فرزند داشته باشیم با هر بار ری رندر شدن کامپوننت پدر ، تمام کاپوننت های فرزند هم ری رندر میشند. اما بدبختی که روی پرفورمنس میاره همینه که این فرزند ها با اینکه پراپ هاشون هیچ تغییری نکردن باید ری  رندر بشن فقط بخاطر اینکه پدرشون ری رندر شده! و این واسه پرفورمنس خوب نیست...ما باید  ری اکت رو مجبور کنیم تا قبل از ری رندر کردن هر کامپوننت بیاد پراپ جدیدش رو با پراپ قبلی مقایسه کنه و اگه فرق داشتن اجازه داشته باشه اون کامپوننت رو ری رندر بکنه و این کار فقط به وسیله react.memo امکان پذیره. memo یه کال بک میگیره که اون کال بک همون کامپوننت ماس که میخوایم هر سری که پدرش ری رندر میشه پراپش چک بشه و در صورت تغییر پراپ این هم ری رندر بشه وگرنه منو سنه نه که پدرم ری رندر شده!توی مثال بالا چون از react.memo استفاده نشده با هر بار اپدیت شدن استیت در کامپوننت App ، کامپوننت ChildComponent هم ری رندر میشه با اینکه هیچ ربطی به استیت نداره و این بنده خدا اصلا حتی پراپ هم نمیگیره که بخواد تغییری هم داشته باشه! پس واسه بهتر کردنش به این شکل از react.memo استفاده میکنیم:میتونید با رفتن به دمو ( لینک دمو )  مثال بالا رو خودتون با memo و بدون اون امتحان کنید تا ببینید با اپدیت شدن استیت در کامپوننت App آیا کامپوننت فرزند ری رندر شده و متن &#x27; child component get re rendered again ! &#x27; لاگ میشه یا نه.6. Code-Splitting with lazy &amp; Suspenseما وقتی میخوایم توی یه صفحه چند تا فایل کامپوننت اضافه کنیم با استفاده از import اینکارو میکنیم که به صورت کاملا استاتیک و موقع کامپایل کردن همه ی اون فایلارو ایمپورت میکنه تو فایلمون و تحویل میده و عملا ما هیچجوره نمیتونیم بگیم که اگه مثلا فلان شرط برقرار بود بیا این کامپوننت رو لود کن وگرنه اگه اون شرطه برقرار نشه اصلا چرا باید اینو لود کنم و حجم رو ببرم بالا و وقت کاربر هم الکی گرفته شه؟بزرگترین موقعیتی که میتونیم با این مشکل مواجه شیم وقتیه که داریم مسیرای مختلف رو توی فایلمون میدیم و برای هر مسیر یه کامپوننت خیلی بزرگ برای رندر شدن توی هر آدرس مشخصی ایمپورت میکنیم خب بهترین چیزی که میتونه اتفاق بیفته اینه که این کامپوننت ها به صورت داینامیک و فقط وقتی مورد نیاز هستن و احضار شدن لود بشن و تا وقتی لازمشون نداریم الکی تایم کاربر سر لود شدن چیزی که قرار نیست حتی چشمش بهش بیفته هدر نره و اینجاس که قابلیت code splitting به وسیله lazy و suspense به دادمون میرسه!این دو دقیقا کارشون همینه که کامپوننت رو در صورت نیاز لود کنن و تا وقتی نیازی نیست زمان سر لود شدن اون کامپوننت ها مصرف نشه تا پرفورمنس سریع تری داشته باشیم موقع لود شدن صفحات.همونطور که توی مثال بالا میبینید قراره هر کامپوننت سر موقعِ نیاز ( عوض شدن مسیر) لود بشه مثلا وقتی مسیر / هستش کامپوننت Home لود بشه وقتی مسیر به panel تغییر پیدا کرد کامپوننت Panel لود بشه و...متد lazy یه کال بک میگیره که این کال بک یه ایمپورت برمیگردونه که داخل ایمپورت مسیر کامپوننتمون رو میزاریم ( خط 5 و 6 مثال بالا)همه ی کامپوننت هایی که با lazy ایمپورت شدن باید داخل suspense قرار بگیرند و fallback ای که به ساسپنس به صورت پراپ داده شده در واقع یه jsx هستش که در فاصله زمانی که کامپوننت در حال لود شدن هستش نشون داده میشه تا حس بهتری به کاربر منتقل کنه.7. React Lazy Load Image Componentفرض کنید از سرور صد تا عکس گرفتید و قراره توی صفحه به کاربر نشون بدید، وقتی کاربر وارد صفحه بشه تک به تک اون صد تا عکس(شایدم بیشتر!) باید لود بشن درحالی که کاربر حتی ممکنه ده تا از اون عکسا هم اسکرول نکنه و نبینه و فقط دوسه تای اول رو ببینه. خب پس در این صورت چرا باید اون عکسهایی که هنوز دیده نشدن و نیازی به لود شدن ندارن وقت مارو بگیرند و وب سایت مارو کند تر کنند؟اینجاس که لایبرری به شدت کاربردی و دوست داشتنی React Lazy Load Image Component میاد وسط و کارش اینه که بیایم بجای تگ img از این استفاده کنیم تا فقط عکس هارو در صورت نیاز لود بکنه و در نتیجه http ریکوئست های کمتری زده شه و پرفورمنس بهتری داشته باشیم و هم اینکه میتونیم قابلیت باحالی مثل placeholder یا effect برای عکسمون داشته باشیم تا زمانی که عکس سنگینه و هنوز کامل لود نشده یه حالت بلور رو نمایش بده یا حالا عکسی که ما توی placeholder قرار میدیم. از این کامپوننت به این شکل استفاده میکنیم:میتونید مثالای بیشتر و داکیومنت کامل این لایبرری رو با سرچ اسمش تو گوگل مطالعه کنید.خب اینا نکات پرفورمنسی بود که اگه درست ازشون استفاده کنیم میتونیم خیلی تجربه خوبی رو برای کاربر هامون رقم بزنیم و همچنین ری اکت دولوپر بهتری باشیم. از این قسمت هم به عنوان نکات پرفورمنسی میشه یاد کرد و هم قسمت دومِ یادگیری هوک ها در ری اکت.خدانگهدار و موفق باشی ?</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Thu, 07 Jul 2022 01:15:15 +0430</pubDate>
            </item>
                    <item>
                <title>با Axios ، راحت تر ریکوئست بزن</title>
                <link>https://virgool.io/@samAghapour/%D8%A8%D8%A7-axios-%D8%B1%D8%A7%D8%AD%D8%AA-%D8%AA%D8%B1-%D8%B1%DB%8C%DA%A9%D9%88%D8%A6%D8%B3%D8%AA-%D8%A8%D8%B2%D9%86-os3ppkgjblej</link>
                <description> آیا از نوشتن .catch های فراوان برای گیر انداختن ارور ها خسته شدین؟آیا از نوشتن پشت سر هم headers و url طولانی api ها خسته شدین؟؟آیا از نداشتن یه ایده درست درمون برای کنسل کردن ریکوئست ها در useEffect (موقع unmount شدن) خسته شدین؟؟؟آیا از نداشتن یه استراکچر تر تمیز و مرتب برای fetch request ها خسته شدین؟؟؟؟کتابخونه دوست داشتنی AXIOS اینجاست تا خستگی رو از تنتون در بیاره?با این کتابخونه دیگه نیازی به استفاده از fetch برای ریکوست ها نیست و  همه ی مشکلاتی که بالاتر عنوان کردم رو میتونیم به راحتی از سر راه برداریم.توی این مقاله قدم به قدم یه استراکچر خفن با AXIOS برای ریکوئست هامون ایجاد میکنیم و از دوباره نویسی های زیادی جلوگیری میکنیم و حین پیاده کردن این استراکچر خط به خط توضیح میدم که چرا و چگونه ؟یه جورایی سبک این پست مثل &quot;یادگیری ریداکس، ساده تراز چیزی که فکر میکنی!&quot; هستش.توی مثال بالا که از fetch استفاده شده ما سه تا ریکوست داریم، حالا اگه بخوایم مشکلات مثال بالا رو نام ببریم اینه که : 1. urlها توی همشون قسمت عظیمیشون تکراری هست ( baseURL ) و فقط تکرار شده. 2. headers توی همشون تکرار شده... 3. بلایی که میخوایم سر ارور بیاریم رو مجبوریم تک تک روی هر ریکوئست با .catch بنویسیماینجاس که میریم سراغ AXIOS1. نصب موارد لازمnpm install axios یا yarn add axios2.ساخت یه پوشه توی src پروژه به اسم Servicesپوشه services شامل سه تا پوشه هست:1.پوشه config دارای یه فایل index.js هست که کانفیگ اولیه رو توش میزاریم و اون تکرار کردن های بالارو تا حدی برطرف میکنیم توشببینید ما درسته axios رو نصب کردیم اما اگه ازش به طور معمولی و بدون کانفیگ بخوایم استفاده کنیم اصلا فرق خاصی با همون fetch نخواهد داشت، برای مثال:اگه مثال بالارو نگاه کنید میبینید که AXIOS بدون کانفیگ همون تکرار کردن هارو داره...حالا چیزی که توی فایل index پوشه ی config قرار میدیم :کاری که کردیم اینه که ما با متد create یه نمونه از axios ساختیم به اسم api (هر اسمی میتونید بدید بجاش) و این متد یه ابجکت به عنوان پارامتر میگیره که تمام کانفیگ رو داخلش میتونیم قرار بدیم، ینی چی؟ ینی اینکه هرچی اینجا قرار بدیم از این به بعد توی همه ی ریکوئست هایی که با api میزنیم به طور خودکار صدا میشه و نیازی نیست برای تک تک ریکوئست ها هدر و base url و ... قرار بدیم?به این شکل:توی عکس بالا اون ریکوئست های بدون کانفیگ کامنت شدن و بجاشون از نمونه ای که خودمون ساختیم استفاده کردیم و دقیقا همون کارهارو انجام میدن اما خیلی تر تمیز و شیک تر ? زیبا نیست؟؟؟نکته درباره مثال بالا: توی متد put و post چیزی که به عنوان پارامتر دوم داریم میفرستیم در اصل همون body هستش و نمیشه که به صورت کانفیگ قرارش بدیم چون به هرحال هر ریکوئست بادی مخصوص خودشو نیاز داره. مثلا توی مثال بالا متد پست داره ایمیل و پسورد رو به عنوان بادی میفرسته تا لاگین کنهنکته : base url چیزیه که به اول url هامون اساین میشه مثلا اگه ما بگیم api(&#x27;/users&#x27;)  اون base url میاد به قبلِ users/ اضافه میشه.نکته دوم: headers برای اینه که توکنی که موقع ثبت نام گرفتیم رو به ریکوئست هامون اساین کنیم تا بتونیم از قابلیت های api استفاده کنیم.نکته سوم: ما برای متد های مختلف ریکوئست مثل post , get , put , delete فقط کافیه از axios به این شکل بگیریمشون: api.post(&#x27;/register&#x27;) , api.put(&#x27;/login&#x27;) و... البته متد get دیفالت هست و در صورت مشخص نکردن متد برای ریکوئست get به طور پیش فرض انتخاب میشه : api(&#x27;/users&#x27;)پس ما از این به بعد بجای axios از api استفاده میکنیم چون الان api یه نمونه از axios هست فقط با کمی کانفیگ درست درمون برای راحتی کار و ما قراره اینو توی دوتا پوشه های همسایه اش ایمپورت و استفاده کنیم.2.پوشه ErrorHandler پوشه ایه که ما با اضافه کردن یه قابلیت به نمونه api خودمون ، از شر .catch های مکرر تا حدودی خلاص میشیم.توی این پوشه یه فایل index.jsx قرار داره که شامل کد زیره:بله! این فایل یه کامپوننته، اما اگه خط آخر رو نگاه کنید میبینید که این کامپوننت هیچی برنمیگردونه و تو خالیه و تنها چیزی که توش بدردمون میخوره همون فانکشن بالاشه که قراره کالبدشکافیش کنیم ( البته این error handling با axios رو میشد به شکلای دیگه هم در آورد ولی خب من روش خودمو که همین باشه توضیح میدم.یه سری نکات مفید که قبل از کالبدشکافی کد بالا اگه با وضعیت های مختلف ارور ها آشنا نیستید بهتره بدونید:ارور با وضعیت 400: این برای وضعیتیه که ریکوئست رو بد زدیم حالا ممکنه یه کلمه رو اشتباه زده باشه توی url یا توی بادی دیتا رو بد فرستاده باشیم و....ارور با وضعیت 401: ما برای استفاده از api به یه توکن نیاز داریم که این توکن رو کاربر وقتی ثبت نام یا لاگین میکنه میگیره و ست میشه توی همون کانفیگی که بالاتر دیدیم، حالا این توکن ها یه زمان انقضا دارن که وقتی فرا برسه دیگه کار نمیکنه و اونجاس  که با این خطای 401 مواجه میشیم و کاربر باید دوباره لاگین کنه تا توکن جدید بگیره یا ام که واسه برخورد نکردن با این ارور باید قبل از زمان انقضا با رفرش توکن بیایم توکن رو زمان انقضاشرو تازه کنیم ( که خود رفرش توکن یه مبحث جدا و مفصله...)ارور 403: این هم برای وضعیتیه که کاربر ممکنه حتی با داشتن توکن نتونه به یه سری چیزا دسترسی داشته باشه و ازشون استفاده کنه که اونوقت این ارور ظاهر میشه و مثلا میگه شما اجازه استفاده از این قابلیت رو ندارید.ارور 404:  وقتی میخوایم یه دیتایی رو از سرور بگیریم که پاک شده (مثلا یه بلاگ از فلان کاربر که کاربر حذف کرده اون بلاگ رو) اونموقع اس که این ارور میاد و میگه که همچین چیزی پیدا نکردم یا همون page not found  معروفارور 429: این برای وضعیتیه که کاربر به صورت رگباری و پشت هم ریکوئست میفرسته و خاااره سرور تار و مار میشه و همچین اروری برمیگردونه که آقا جون جدت یواشرهگیر ها یا interceptorsهمونطور ک توی مثال بالا میبینید ما نمونه api خودمون رو ایمپورت کردیم و از چیزی به اسم interceptors استفاده کردیم و interceptor ها دوتا هستن یکی برای request و یکی برای response اولی میاد یه سری بلا سر ریکوئست اولیه ما میاره و بعد میفرستتش سمت سرور،  ولی دومی (response) که ما توی مثال استفاده کردیم، بعد از اینکه ما ریکوئست رو زدیم و جوابی از سرور برگشت، قبل از اینکه اون جواب به then و catch برسه به ایشون میرسه و حالا ما با متد use که دوتا ارگومان داره میتونیم یه بلایی سر این ریسپانسی که از سرور گرفتیم بیاریم و بعد بفرستیمش سمت then و catchمتد use دوتا کال بک میگیره که...اولی رو فقط وقتی اجرا میکنه که ریسپانسی که از سرور گرفتیم وضعیتش زیر یا مساویه 200 باشه (موفقیت آمیز) و دیگه دومین کال بک رو در این صورت اجرا نمیکنه.دومی رو فقط وقتی اجرا میکنه که ریسپانسی که از سرور گرفتیم وضعیتش بیشتر از 200 باشه ( شکست خورده) و دیگه اولین کال بک رو در این صورت اجرا نمیکنه.توی مثال بالا برای فانکشن اول که کار خاصی با ریسپانس نداریم و در صورت موفقیت امیز بودن، ریسپانس رو همونطوری میفرستیم میره واسه .thenاماااا وقتی ریسپانس شکست خورده باشه معمولا بیشتر اوقات وضعیتش یکی از ایناس که اکثرشون رو میشناسید 401 , 400 , 403 , 429 و حالا ما اینجاس که توی کال بک دوم برنامه ها داریم واسه این ارور ها.کال بک دوم یه error به صورت ارگومان گرفته که یه پراپرتی response داره که ابجکته و شامل یه سری پراپرتی هاس که ما اینجا فقط دوتاشو کار داریم : یکی وضعیت یا status و دیگری پیغامی که از بک اند برای اون ارور داده یا همون data.message حالا اومدیم گفتیم که هروقت ارور 400 گرفت بیا با promise.reject یه اعلام شکست بکن و در ادامش گفتیم یه الرت هم به کاربر بده و پیغامی که به کاربر میدیم میتونه قشنگ همون پیغامی باشه که ازبک اند میاد error.response.data.messageنکته : promise.reject رو توی همه ی حالات برمیگردونیم که وقتی ریسپانس از این مرحله میگذره و میره به then و catch ، سیستم بدونه که کدوم باید اجرا شه و کدوم نهتوی شرط بعدی گفتیم که اگه وضعیت 403 بود ریجکت کن و بعدش الرت بده که شما در سطح این قابلیت نیستی و راه باز جاده دراز!توی شرط بعدی که ارور 404 هست میل سخن گفتن نیست و فقط ریجکتتوی شرط بعدی که ارور 429 هست ریجکت و بعد، آلرت دادیم که آراااام وحشیتوی شرط آخر که 401 هست به انقضای توکن برخوردیم و از اونجایی که که توکن و بقیه اطلاعاتی که موقع ثبت نام و لاگین میگیریم رو توی لوکال استوریج ذخیره کردیم، همشون رو پاک میکنیم و کاربر رو دوباره به صفحه لاگین میفرستیم تا دوباره لاگین کنه و با توکن جدید ادامه بده.در نظر داشته باشید شما میتونید هر خلاقیتی به خرج بدید و واسه ارور ها ریسپانس های قشنگ تری بزک دوزک کنید و صرفا دلخوش به یه آلرت خشک و خالی نباشید.حالا این کامپوننت AxiosErrorHandler رو هر جا صدا بزنید و اونجا ریکوئستی با api بزنید اون interceptor میپره وسط و کارشو میکنه و درصورت ارور اون اجی مجی های شرطی که نوشتیم رو اجرا میکنهخب من میزارمش توی &quot;src/index.js&quot; که توی کل فیهاخالدونِ پروژه رهگیری انجام بشه:3.پوشه Requests پوشه ایه که ما تموم ریکوست هامون رو با دسته بندی های مختلف به صورت فانشکن های async تعریف و اماده میکنیم تا برای استفاده و دسترسی به هر ریکوئستی فقط کافی باشه اون فانکشن موردنظر رو از این پوشه ایمپورت و صدا بزنیم و ریسپانسی که میگیریم رو استفاده کنیم.ما معمولا ریکوئست هامون دسته بندی های مختلفی دارن مثلا یه سری ریکوئست داریم مربوط به authentication هست مثلا ریکوئست ثبت نام و یا لاگین و یا عوض کردن رمز عبور و یا فراموشی رمز عبور و... و یا مثلا یه سری ریکوئست داریم مربوط به خود کاربر هست مثلا گرفتن اطلاعات ثبت شده کاربر ، عکس کاربر ، پست های کاربر و.... بهتره این دسته بندی هارو توی پوشه Requests هرکدوم رو توی پوشه جدا بزاریم مثلا:توی مثال بالا ما توی هر پوشه یه فایل index.js داریم و توی این فایلا تک به تک فانکشن هایی که لازم داریم رو میزاریم :عکس بالا مثالی از فایل index پوشه auth هست که سه تا فانکشن مختلف برای ریکوئست های مختلف داریم که همه این ریکوئست ها مربوط به aithentication هست و اکسپورت شده اند تا ما بتونیم هر جا مثلا به ثبت نام نیاز داریم فقط این فانکشن رو ایمپورت و صداش کنیم و تمااام.نکته: یادتون باشه این فانکشن ها async هستن و ما باید به صورت asyncصداشون کنیم و منظر جوابی که از سرور میگیرن و برمیگردونن باشیم ( با await یا با .then)اینم یه مثال نهایی مثل بالا ممتها از پوشه blogs که فقط ریکوئست های مربوط به بلاگ هست:بحث  fetch cancellationبعضی وقتا میشه که ما توی useEffect ریکوئستمون رو صدا میزنیم و خب مسئله ای که هست و بعضی وقتها دیدم رعایت نمیشه اینه که ما وقتی توی این هوک یه ریکوئست میزنیم هر سری داره هی این ریکوئست رو میزنه و حتی وقتی که دیگه کامپوننت رو بستیم (به اصطلاح unmount کردیم) باز هم اون ریکوئسته داره زده میشه و اینجاس که شاید همچین هشداری رو دیده باشید:این هشدار میده که عزیز من کامپوننتت بسته شده و بهش احتیاجی نداری بیا ولی با این حال داری ریکوئست میزنی!کاری که ما باید انجام بدیم اینه که وقتی داخل useEffect یه ریکوئستی صدا میزنیم آخرش توی همین هوک یه فانکشن برگردونیم که توش اون ریکوئست رو کنسل کنیم ( این فانکشنی که برمیگردونیم وقتی اجرا میشه که کامپوننت unmount میشه) حالا روشی که میتونیم با axios اینکارو راحت انجام بدیم به این شکله:ما به عنوان پارامتر دوم api،  بهش یه ابجکت میدیم که پراپرتی signal برابر باشه با کنترلری که ساختیم و توی فانکشن cleanup، متد abortرو از کنترلری که ساختیم صدا میکنیم و این کار ریکوئست مارو کنسل میکنه و دیگه اون وارنینگ هم نمیگیریم و پرفورمنس هم به مراتب بهتر میشه.خب این مقاله اینجا به پایان میرسه و امیدوارم کار با این کتابخونه دوست داشتنی و خفن رو یاد گرفته باشی و بیشتر و بهتر با ریکوئست ها دلبری کنی :)خدانگهدار و موفق باشی?</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Sun, 20 Mar 2022 17:04:24 +0330</pubDate>
            </item>
                    <item>
                <title>پشت پرده ی جاوااسکریپت! Promise ها چگونه کار میکنند؟</title>
                <link>https://virgool.io/@samAghapour/sam-aghapour-promises-qtm8bcbxgehv</link>
                <description>promises in javascript سلام دوستان?وقتی یه زبانی رو یاد میگیرم دوس دارم برای مسلط شدن بهش بفهمم فلان مبحث در پشت پرده ی این زبان چجوری هندل میشه تا بتونم موقع استفاده ازش درک بهتری داشته باشم و در نتیجه باگ کمتری تولید کنم.اگه شما هم جزء اون دسته برنامه نویسایی هستید که دل و روده مباحث رو تا نریزن بیرون آروم نمیگیگیرن بیاید شروع کنیم?نکته: اگه درمورد event loop , callback queue , call stack و کلا نحوه هندل شدن توابع async در جاوااسکریپت  که پیش نیاز مقاله فعلی هستند، چیزی نمیدونید، لطفا لطفا لطفا قبل شروع این مقاله ، این موارد رو یاد بگیرید که یه مقاله هم راجبشون نوشتم میتونید با کلیک روی این لینک اول اون رو مطالعه کنید و بعد به این مقاله وارد بشید.یکی از این مباحث مهم که میخوایم دل و رودش رو بریزیم، promise ها در جاوااسکریپته. حالا چیزایی که ما قراره توی این مقاله به عنوان موضوع اصلی و مکمل هاش یاد بگیریم:همه چیز راجب Promise ها و نحوه هندل شدن و چیستی و چرایی و کلی مثال از دنیای واقعی و کد و...فانکشن هایی با عنوان callback و موضوعی به اسم callback hellچگونگی به وجود اومدن async در جاوااسکریپتمبحث فوق العاده ای با عنوان microtask queue و macrotask queueسینتکس async / await دیباگ کردن با بلاک های try / catch / finallyریکوئست زدن با Promise.all و Promise.allSettledقول یا Promise در جاوااسکریپتبزارید این مبحث رو با یه مثال از دنیای واقعی شروع کنیم:پسری رو در نظر بگیرید که دو هفته دیگه تولدش هست و مادرش بهش قول میده که تا دوهفته دیگه یه کیک براش میپزه و توی این دو هفته که مادره مشغول انجام کارای کیک هست پسره مثل شلغم نمیشینه منتظر بشینه تا مادره کیک رو بپزه و بعد بره مابقی کارای تولد رو انجام بده! اینطوری همه چی بلاک و معلق میشه بخاطر یه دونه کیک :/ ، بلکه پسره طی این زمان به بقیه کاراش میرسه از جمله تهیه کردن بقیه چیزا واسه جشن تولد و... حالا این وضعیتِ قولی که مادر داده تا زمانی که تکلیفش مشخص نشده در حالت Pending یا انتظار قرار داره...  وقتی تکلیفش مشخص شه اون حالت pending به یکی از دو حالت دیگه میتونه تغییر بکنه:حالت موفقیت آمیز یا fulfilled یا resolvedحالت ردشده یا rejectedاگه فرض رو بر این بگیریم که مادره مریض میشه و نمیتونه کیک رو بپزه پسره قراره یه واکنشی نشون بده(ناراحت میشه) و اگه مادره اتفاق بدی نیفته و بتونه کیک رو بپزه پسره یه واکنش دیگه نشون میده (خوشحال میشه) و در نتیجه چه کیک پخته شه چه نشه یه چیز رو در نهایت هر حالتی اتفاق بیفته پسره انجام میده و اون برگزار کردن جشن هست.عکس بالا مثالی که ما زدیم رو قشنگ نشون میده. وقتی پسره نمیشینه منتظر کیک بمونه و همزمان به بقیه کاراش میرسه به اون پروسه ای که کیک داره طی میکنه میگن asynchronous یا غیر همزمان. توی دنیای جاوااسکریپت هم اینطوری میشه گفت که این زبان به علت single thread بودن فقط میتونه یه خط کد رو در یک زمان انجام بده و نه دوتا پروسه رو همزمان!و یه زبان synchronous هست. پس پروسه های async یا غیر همزمان مثل ajax request ( گرفتن اطلاعات از سرور) در جاوااسکریپت چجوری هندل میشن؟  همون چیزی که موضوع امروز بحثمونه Promise ها ?وقتی جاوااسکریپت به یه خط غیر همزمان مثل  ajax request میخوره(fetch یا axios و...)، میدونه که این یه مقدار زمانی رو طول میکشه تا بره و دیتارو بگیره و بیاره پس بجاش یه آبجکت برمیگردونه که بهش promise یا قول گفته میشه، حالا بیاید چک کنیم این ابجکت شامل چه پراپرتی هایی هست:promiseobjectتوخط بالا یه ریکوست زدیم تا از سرور یه سری اطلاعات بگیریم و بریزیمش توی متغیر data اما تا این دیتا برسه یه مقدار طول بکشه پس جاوااسکریپت مثل شلغم نمیشینه  بمونه تا این بره از سرور یه چیزی بگیره بیاد بعد مابقی کدهارو انجام بده چون توی این شرایط ابجکتی داره به اسم promise که اونو برمیگردونه و به بقیه کاراش میرسه. حالا این ابجکت شامل چیزایی هست که توی تصویر هم مشاهده میکنید:یک پراپرتی با اسم promiseState یا وضعیت که شامل یکی از سه حالاتی که بالاتر هم گفتیم میتونه باشه: 1.pending یا انتظار که یعنی هنوز در حال گرفتنه و تکلیف مشخص نیست. 2.fulfilled یا موفقیت آمیز که یعنی دیتارو با موفقیت گرفته 3.rejacted یا ردشده که یعنی دیتارو نتوسنته بگیره و با یه خطایی مواجه شدهیک پراپرتی با اسم promiseResult یا نتیجه داریم که مقدارش وابسته به پراپرتی promiseState تغییر میکنه. نمونه در عکسهای زیر:وقتی وضعیت pending باشه نتیجه برابر با undefined هستوقتی وضعیت rejected باشه نتیجه برابر با پیغامِ اروری هست که میدهوقتی وضعیت fulfilled باشه نتیجه برابر با چیزی هست که از سمت سرور اومده3.ابجکت پروتوتایپی که اگه مقاله پروتوتایپ رو خونده باشید میدونید که این یه ابجکتیه که ایشون به ارث بردن و داخلش سه تا متد هست که وابسته به پراپرتی promiseState یا وضعیت، به طور اتوماتیک اجرا میشن که یکی یکی بررسی میکنیم:متد catch که یک فانکشن با یک پارامتر(که مقدارش همون مقدارِ پراپرتی promiseResult هست) میگیره و فقط و فقط زمانی که وضعیت rejacted باشه اون فانکشن رو اجرا میکنه و اگه وضعیت جور دیگه ای باشه این اصلا اجرا نمیشهمتد then که یک فانکشن با یک پارامتر(که مقدارش همون مقدارِ پراپرتی promiseResult هست) میگیره و فقط و فقط زمانی که وضعیت resolved باشه اون فانکشن رو اجرا میکنه و اگه وضعیت جور دیگه ای باشه این اصلا اجرا نمیشهمتد finally  که  با دوتای بالا فرق داره و وضعیت چه rejacted باشه چه resolved ، بازم اجرا میشهتوی مثالی که در اول مقاله زدیم هم، واکنش ناراحت شدنِ پسر به قول مادرش  مثل اجرا شدن فانکشن داخلِ متدِ catch هست ،واکنش خوشحال شدنِ پسر به قول مادرش  مثل اجرا شدن فانکشن داخلِ متدِ then هست، و برگزار کردن تولد در هر دو صورت مثل اجرا شدن فانکشن داخلِ متدِ finally هست.حالا یک مثال از این متد های catch , then , finally بزنیم برای وضعیت های مختلف:توی مثال بالا اول وضعیت پرامیس pending هستش بعدش وضعیت rejected شد(حالا به هر دلیلی) و با rejected شدن وضعیت، فانکشن یا callback داخلِ catch اجرا شد و بعدش فانکشن داخلِ finally اجرا شد.توی مثال بالا اول وضعیت پرامیس pending هستش بعدش وضعیت resolved شد و با resolved شدن وضعیت، فانکشن یا callback داخلِ then اجرا شد و بعدش فانکشن داخلِ finally اجرا شد.مبحث callback ها در جاوااسکریپت + پیدایش asyncتوی مثالای بالا به callback اشاره شد که شاید برای بعضیاتون سوال پیش بیاد که چی هستش؟دوستان به فانکشنی که به عنوان آرگومان پاس داده میشه به یه فانکشن دیگه و بعد از اتمام پروسه ی داخل اون فانکشن، فانکشن پارامتر اجرا میشه callback گفته میشه.اگه یکم بخوام برگردم عقب، وقتی جاوااسکریپت نمیتونست کارای async انجام بده و مجبور بود بخاطر single thread بودن کلی بلاک شه و معطل بمونه تا یه پروسه ی نسبتا طولانی به اتمام برسه و بتونه خط های بعدی رو اجرا بکنه. بعدش برای حل مشکل بلاک شدن روی پروسه های طولانی مدت، اینترفیس یا رابطی به اسم asynchronous به وجود اومد که با گرفتن یه فانکشن به عنوان پارامتر که همون callback خودمونه، دیگه جاوااسکریپت مجبور نبود بلاک ومعطل بمونه و در عوض میگفت در حین اینکه این پروسه طولانی انجام میشه من میرم سره بقیه کدا ولی تو بیا این کال بک رو بگیر و وقتی این پروسه تموم شد فوراََ اجراش کن.نکته: کال بک ها asynchronous نیستند و عملا sync هستند، فقط قابلیت این رو دارند که بتونیم باهاشون کدای async اجرا بکنیم و پروسه های async یا غیرهمزمانی مثل ajax request بعد از fulfilled شدن، کال بک خودشون رو صدا میکنن تا یه بلایی سر دیتایی که برگردوندن بکنن.بیاید یه مثال کد از کال  بک ها  ببینیم:در مثال بالا وقتی getData اجرا شده ajax request رو انجام داده و پارامتر دوم یه کال بک داده تا هروقت تکلیف دیتایی که داره از این ریکوئست برمیگرده مشخص شد این کال بک رو دیتا انجام بده و پارامتری که کال بکمون میگیره همون دیتا هستش.مشکل callback hellحالا مشکلی که این کال بک ها به وجود اوردن و باعث به وجود اومدن promise ها شدن اینه که وقتی بخوایم بلایی سر دیتا توی کال بک بیاریم که خودش async هست باید بازم مداخل اون کال بک ، کال بکِ دیگه ای رو انجام بدیم و اگه بازم داخل همون کال بک یه پروسه async دیگه بریم باز یه کال بکِ دیگه و.... زنجیره ای از کال بک ها که پشت هم پس از اون یکی اجرا میشن و این خیلی کد رو شلوغ و نامرتب میکنه که بهش callback hell گفته میشه.توی نمونه بالا ما بعد از بدست اوردن دیتا اولین کال بک صدا زده میشه و بعد از اتمام اون کال بک، ریکوئست دوم زده میشه و کال بک بعدی انجام میشه و به ترتیب این کار چند بار یکی پشت دیگری انجام میشه و همونطور که تو عکس میبینید یه جهنم واقعی از کال بک هارو میبینید که در مقیاس های بزرگتر حتی خیلی بدتر میتونه باشه و اینکه گرفتن ارور و هندل کردنش هم توی این روش خیلی عجیب غریب و سخت تره و اینطوری شد که promise ها اومدن تا با then. و catch. کارمون رو راحتتر کنن.مبحث Promises chainingپرامیس ها اومدن تا کار مارو از لحاظ پیچیدگی کال بک های تو در تو راحت کنن اما مثل اینکه کافی نبود! وقتی بخوایم مثالی که توی callback hell زدیم رو با then. و catch. پیاده کنیم اگرچه خوانا تر میشه کدمون اما ما بازم دنبال روش راحتتری هستیم. بیاید یه مثال ببینیم:Promises chainingتوی مثال بالا میبینید که ما یه دیتایی رومیگیریم و یه بلایی سرش میاریم (در این مثال فقط لاگ میگیریمش)  اما بعدش با یه ریکوئست دیگه یه پرامیس دیگه برمیگردونیم و بعدش یک .then دیگه میزاریم و دیتای این ریکوئست جدید رو هم یه کاریش میکنیم(در این مثال لاگ میگیریم) و به همین ترتیب چندین پرامیس پشت سر هم میفرستیم و با then ها یه بلایی سرشون میاریم که به این عمل، زنجیره پرامیس ها یا promises chaining گفته میشه.پیدایش سینتکس async / awaitبرای حل کردن مشکل زنجیره ای شدن پرامیس ها، جاوااسکریپت در es8 سینتکس جدیدی که از همون پرامیس ها استفاده میکنه معرفی کرد تا با شبیه کردن بیشترِ کدهای async به sync دیگه خیلی خیلی خوانایی کد رو راحت تر کنه.async / awaitطبق مثال بالا سینتکس async / await به اینصورت هست که:1.  به فانکشنی که داخلش ریکوئست اتفاق میفته، کلمه async بهش اضافه بشه تا این فانکشن قابلیت async رو داشته باشه2. به قبل ریکوئستی که میدیم کلمه await داده بشه تا جی اس عملیات داخل فانکشن رو (فقط داخل فانکشن رو) تا زمانی که تکلیف این ریکوست مشخص شه ، متوقف کنه3. بعدش هر کاری که انجام بدیم دقیقا بعد از روشن شدن تکلیف اون پرامیس انجام میشه و دیگه نیازی به نوشتن .then و.. نیست.نکته ی جالب توجه اینجاست که الان فانکشن getData،  خودش یه پرامیس برمیگردونه چون یه فانکشن async هستش و پروسه داخلش به طور غیر همزمان داره هندل میشه و ما اگه بخوایم میتونیم بعد از صدا زدن این فانکشن بهش .then و... اضافه کنیم و کار خاصی رو انجام بدیم:همونطور که میبینید ما با صدا زدن getData و اضافه کردن then بهش اول توی حالت پندینگ هست این فانکشن و بعدش برای هر ریکوست که داخل فانکشن زده شده عملیاتی که میخوایم رو انجام داده(در این مثال گرفتن هر دیتا و لاگ گرفتنش) و بعد از انجام موفقیت امیز همشون اومده حالا عملیاتی که داخل .then تعریف کردیم رو انجام داده ( که توی این مثال لاگ گرفتن جمله all requests are done هست ) اگه پروسه ی داخل فانکشن وضعیت rejected برمیگردوند بجای .then ، کال بک داخل .catch رو اجرا میکرد.مبحث  try / catch / finallyما برای امتحان کردن کدامون میتونیم از بلاک هایی مثلا try و catch و finally استفاده کنیم:توی مثال بالا ما ریکوئست هامون رو داخل بلاکِ try گذاشتیم و اگه مشکلی نباشه که به درستی اجرا و بدون رفتن تو بلاکِ catch به finally میره و بعد تموم میشه و اگه بلاک finally نباشه هم که بازم تمومه. حالا توی این مثال سه تای اول رو اجرا و وقتی توی jobs ارور میگیره میپره توی بلاک catch و بعد از اون بلاکِ finally.هر خطی از کد که داخل بلاکِ try نوشتیم ارور داشته باشه دیگه جاوااسکریپت بقیه خط های داخل بلاک رو اجرا نمیکنه و یه راست میره کدی که داخل بلاک catch نوشتیم رو اجرا میکنه پارامتری که برابر با همون ارور هستش رو میگیره و میتونیم باهاش هرکاری کنیم (توی این مثال لاگ گرفتیم تا ببینیم ارور چیه) و در نهایت اگه بلاک finally وجود داشته باشه اجراش میکنه و در صورت وجود نداشتن به بقیه کاراش ادامه میده.نکته :موقع استفاده از بلاکِ try ،استفاده از بلاک catch به همراهش ضروری هستش چون به هرحال ما داریم یه چیزی رو امتحان میکنیم تا اگه اروری داشت بگیریمش وقتی catch نباشه با چی بگیریمش؟اما بلاکِ finally ضروری نیست و میتونیم بزاریمش یا نزاریمش.این بلاک ها مارو توی دیباگ کردن کد ها خیلی کمک میکنن و مخصوصا موقع استفاده از  async / await جای خالیِ catch. و then.  رو برامون پر میکنن.مبحث microtask queue و macrotask queueتوی مقاله ی &amp;amp;amp;quot;پشت پرده ی جاوا اسکریپت! توابع asynchronous چطور کار میکنند؟&amp;amp;amp;quot; ، اینو فهمیدیم که جاوااسکریپت تسک های sync رو میریزه تو call stack و کال بک ها میرن داخل web api و وقتی زمان اجراشون رسید داخل callback queue ریخته میشن، حالا این callback queue اسمهای دیگه ای از جمله macrotask queue و یا task queue هم داره که اینجا با macrotask queue بهش اشاره میکنم.حالا یه چیز جدیدی که توی اون مقاله نگفتم و اینجا جای مناسبیه که بازش کنم microtask queue هستش،ببینید موضوع اینه که همه ی کال بک ها داخل macrotask queue یا همون callback queue ریخته نمیشند.فقط کال بک هایی که زمان بندی شدن و یا زمان بندی مشخصی دارند مثل کال بک های setTimeout , setInterval و event handler ها به داخل این صفِ macrotask queue ریخته میشند اما کال بک های پرامیس ها یا همون کال بک هایی که داخل then مینویسیم به محض مشخص شدن وضعیت پرامیس از web api به داخل یه صف جدا و خاص به اسم microtask queue ریخته میشندحالا اولویت event loop برای انجام دقیقا به این ترتیبه: اولویت اولِ event loop با call stack هستش که کد های sync داخلش ریخته میشنداولویت دومِ event loop با microtask queue هستش که کال بک های پرامیس داخلش ریخته میشند.اولویت سومِ event loop با macrotask queue یا callback queue هستش که کال بک های زمان بندی شده داخل ریخته میشند.گیف زیر خیلی روان و واضح این اولویت بندی رو نشون میده:اولویت بندی event loopحالا یه سوال! به نظرتون خروجی کد های زیر چیه و به چه ترتیبی نمایش داده میشوند؟پاسخ :خط اول به دلیل sync بودن به داخل call stack ریخته میشه، خط بعدی که setTimeout هستش کال بکی که داره به web api میره و به دلیل اینکه زمان اجراش صفر ثانیه هستش درجا میره تو صف macrotask queue، خط بعدی که پرامیس هستش کال بکی که داره به web api میره و به محض resolve شدنِ وضعیتِ پرامیس، این کال بک به صف microtask queue میره، خط بعدی که کد sync هست به call stack میره.حالا event loop با اولویت بندی که داره اول کدای داخل call stack رو اجرا میکنه، ینی اول کلمه !Start و بعدش کلمه !End نمایش داده میشه و بعدش که میبینه call stack  خالی شده میره سراغ اولویت دومش که microtask queue هست و کال بک پرامیس که داخلش هست رو اجرا میکنه ینی کلمه ی !Promise نمایش داده میشه و بعد از اون میره سراغ اولویت اخرش که macrotask queue هستش و کال بکی که متعلق به setTimeout هست رو اجرا و کلمه !Timeout رو نمایش میده. بیاید این مراحل رو به صورت گیف ببینیم:فانکشن سازنده پرامیس یا Promise constructorشاید موقعیتی پیش بیاد که بخواید خودتون یه ابجکت پرامیس بسازید که خب برای تکمیل شدن این مقاله یه نگاهی هم به این قابلیت میندازیم:توی مثال بالا ما پرامیسی ساختیم که مقدار resolved data رو با وضعیت Fulfilled برمیگردونه.توی مثال بالا ما پرامیسی ساختیم که مقدار Error : rejected رو با وضعیت rejected برمیگردونه.مبحث ()Promise.all و ()Promise.allSettledممکنه لیستی از ریکوست ها داشته باشیم که بخوایم همشو یکجا ریکوست بزنیم و یکجا هم مقدار همشونو بگیریم، خب متد all. از پرامیس این قابلیت رو بهمون میده و یه پارامتر که باید یک آرایه از ریکوئست هامون باشه رو میگیره و یکی یکی انجامشون میده و یه پرامیس برمیگردونه حالا اگه هیچکدوم از این ریکوئست ها به ارور نخورن با وضعیت fulfilled و یه آرایه متشکل از دیتای برگشتی از هر ریکوئست رو به عنوان نتیجه برمیگردونه:حالا اگه حتی یکی از ریکوئست هامون ارور داشته باشه دیگه دیتای برگشتی از بقیه ریکوئست ها هم نشون نمیده و بیخیالشون میشه و  فقط ارور رو نشون میده. به بیانِ دیگه این متد میگه یا همه یا هیچکدوم:Promise.allبرای حل این مشکلِ &quot;یا همه یا هیچکدوم&quot; هم جاوااسکریپت عزیز یه متد دیگه داده بیرون به اسم ()Promise.allSettled که میاد یه آرایه برمیگردونه که داخلش برای هر ریکوئست یه ابجکت قرار داده با پراپرتی های status که مقدارش rejected یا fulfilled هست و یه پراپرتی با اسم value که مقدارش در صورت fulfilled بودن برابر با دیتای برگشتی و در صورت rejected بودن اسم این پراپرتی به reason تغییر و مقدارش برابر با متن ارور هست:Promise.allSettledتوی عکس بالا میبینیم که با اینکه ریکوئست دوم ارور برگردونده این متد نیومده بقیه رو هم بیخیال شه و برای هر ریکوئست، یک آبجکتی رو با ریسپانس برگشتیِ اون ریکوئست که حالا چه دیتا باشه چه متن ارور، توی آرایه قرار داده.مبحث پرامیس ها و تمام مکملاتش اینجا به پایان میرسه و امیدوارم که به درک خوبی از نحوه هندل شدن پرامیس ها در جاوااسکریپت و همه ی موضوعات فرعی که بیان شد رسیده باشید.خدانگهدار و موفق باشید?</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Fri, 04 Feb 2022 22:21:28 +0330</pubDate>
            </item>
                    <item>
                <title>صفر تا صد oop در جاوااسکریپت! قسمت دوم: 4 اصل oop</title>
                <link>https://virgool.io/@samAghapour/sam-aghapour-oop-4pillars-o0unx70mgbcm</link>
                <description>object-oriented programmingسلام دوستان?توی مقاله قبلی ورود به دنیای oop یا برنامه نویسی شی گرا در جاوااسکریپت رو با یادگرفتن مبحث prototype و class  ها شروع کردیم و توی این قسمت قصد داریم که این ماجراجویی رو با یاد گرفتن چهار اصل مهم در برنامه نویسی شی گرا ، تموم کنیم.قبل از شروع اصول شاید بپرسین برنامه نویسی شی گرا ینی چی اصلا؟؟!برنامه نویسی شی گرا یا object-oriented programmin ، یک الگو بر پایه آبجکت ها هستش. ینی یه روش یا الگو از کد زدن که توش سر و کارمون با آبجکتی هست که دارای دیتا یا به اصطلاح پراپرتی و متد هایی هستند و از روی اون آبجکت، آبجکت های دیگه رو میسازیم.حالا به اون کلاسی که از روش ابجکت میسازیم و دارای متد و پراپرتی هستش bluprint میگن که به معنای &quot;طرح&quot; هم هستش و به آبجکتهای ساخته شده از اون instance میگن که به معنای &quot;نمونه&quot; یا &quot;مثال&quot; هستش و توی قسمت اول باهاشون آشنا شدیم و اگه بخوام یه مثال از دنیای واقعی بزنم ماشین یه آبجکت هستش که دارای کلی متد و پراپرتی مثل گاز دادن، ترمز کردن، بوق زدن و... هست یا مثلا انسان یه ابجکت هست که دارای متد و پراپرتی هایی مثل قد و وزن و رنگ چشم و... هست.4 اصل یا ستون برنامه نویسی شی گرا1. اصل اول: ENCAPSULATION یا کپسوله سازیاین اصل میگه شما باید بیای همه ی متغیرا، فانکشن های مربوط به یه چیز رو جمع کنی و بریزی داخل یه آبجکت یا به اصطلاح کپسوله بکنیشون، طوری که هیچ چیز غیر مرتبطی از بیرون نتونه به این پراپرتی ها و متد ها دسترسی داشته باشه و دستکاری و یا حتی استفادشون بکنه مثلا ما کلی متد پخش و پلا داریم توی اسکوپ گلوبال از جمله گاز دادن و ترمز کردن و بوق زدن و پدال و و صندلی و.... خب اینا همه باید توی یه ابجکت که همشون بهش مرتبط هستن باشن به اسم ماشین تا برای مثال متغیری مثل گاو نتونه به گاز دادن دسترسی داشته باشه :| (مطمعنا گرفتین نیت حرفم رو مثالای بهتر رو به ذهن کاوشگر خودتون میسپرم).کپسوله کردنتوی مثال بالا اول اومدیم متد هارو توی اسکوپ گلوبال خیلی آزاد و رها نوشتیم و الان بدیش اینه که هر کس و ناکسی هر جا میتونه به با یه کلمه ()start نوشتن بهش دسترسی داشته باشه اما توی راه دوم ما کپسوله سازی کردیم و ریختیمشون داخل ابجکت car تا همه بدونن که آقا فقط اینا فقط مربوط به ماشینه شما برای چیزایی مثل خوش آمد گویی نباید از این متد ها استفاده کنی!البته تعریف کپسوله کردن رو به همینجا بسنده نمیکنیم، توی اصل encapsulation ما عملا متد ها و پراپرتی های مرتبط به هم رو میریزیم داخل یه ابجکت و میگیم که این متدا اماده اینجا هستند و هر آبجکتی که از این ابجکت نمونه سازی شد میتونه راحت به این دسترسی داشته باشه و استفادش کنه.در واقع اینطوری هم میشه گفت که هدف اصلی encapsulation ، جمع کردن همه ی متدا و پراپرتی های مرتبط توی یه ابجکت و غیر قابل دسترس مستقیم کردنشون هست و با متد های getter , setter ای که تعریف میکنه میتونید به فلان پراپرتیش دسترسی داشته باشید که البته توی عکس بالا به این اشاره نشد. مثال از چیزی که گفتم:دسترسی یا دستکاری مستقیم ممنوعتوی عکس بالا اگه پراپرتی های name و speed رو کپسوله نمیکردیم همه جا و همه جوره قابل دسترس بود و میشد با لاگ گرفتن name یا speed مستقیما بهش دسترسی داشت اما وقتی کپسوله میکنیمشون باید یه مقداری رو با فانکشن setter ای که تعیین شده بهش بدیم و بعد با فانکشن getter مقدارشو بگیریم.توی عکس بالا که مثالی از ماشین در دنیای واقعی هست ، ماشین یه ابجکته که همه ی پراپرتی هایی مثل بدنه و چرخ و موتور و همه متدهایی مثل حرکت و خاموش و روشن شدن و... رو توی خودش داره و ما فقط کافیه صداش بزنیم و کپسوله کردن میگه میخوای ماشینو روشن کنی؟ متد start رو صدا بزن و حالشو ببر.نتیجه: اصل ENCAPSULATION، پیچیدگی کد رو با زیر یه چتر(ابجکت) بردن دیتای مرتبط کمتر میکنه و از دسترسی مستقیم داشتن به این دیتا در محوطه بیرونی در جهت بالا بردن امنیت این دیتا (پراپرتی و متدها) جلوگیری میکنه.2. اصل دوم: ABSTRACTION یا تفکیک و یا انتزاعاین اصل کارش اینه که اطلاعات غیر ضروری رو مخفی میکنه و فقط چیزای ضروری رو نشون میده ینی شما نیازی نیست بدونی متد استارت یا بوق زدن چه پروسه ای رو طی میکنه تا نتیجه رو برگردونه و فقط متد رو صدا میکنی و استفادش میکنی.abstraction: show essentials and hide unnecessarily dataتوی عکس بالا راننده به این فکر نمیکنه که وقتی پدال رو فشار میده &quot;چگونه&quot; ماشین حرکت میکنه و فقط اینو میدونه که با فشار دادن پدال گاز(یا صدا زدن متد حرکت) این ماشین قراره &quot;چه کاری&quot; رو انجام بدهمثالش توی کد:صدا زدن استارت بدون توجه به اینکه چجوری کار میکنهتوی مثال بالا میبینیم که ما کاری نداریم متد استارت &quot;چجوری&quot; کار میکنه که &quot;...starting&quot; نمایش داده میشه، ما فقط میدونیم که با صدا زدن قراره &quot;چی&quot; نشون بده و abstraction همینه و موضوع دیگه اینکه با پرت کردن ارور (throw new Error) داخلِ هر متدی داریم صراحتا میگیم که نمیتونی از این متد بدون رونویس کردنش برای هر نمونه ابجکت استفاده کنیم و باید بگی این متد برای هر ابجکت چی برمیگردونه و همینطور نمیتونی از خود ابجکت Car به طور مستقیم استفاده و ازش نمونه بسازی و فقط با فرزنداش میتونی اینکارو بکنی. اما چرا باید برای بعضی متدا ارور پرت کنه تا مجبور بشی رونویسش کنی ؟؟ سوال خوبیه . جوابش:فرض کنید ما متدی مثل start که نیازی به بازنویسیش هم نداریم برای همه صدا میزنیم و یکسانه اما اگه بخوایم بگیم که تسلا استارتش یه فرقایی با ولوو و مابقی ابجکت های نمونه داره مجبوریم متد استارت رو از توی Car تغییر بدیم که اینطوری این تغییر روی همه ی ابجکت ها اعمال میشه ! و ما نمیخوایم این اتفاق بیفته و میخوایم که اون متد فقط برای اون ابجکت بازنویسی بشه پس در مثال بالا هم سوخت ماشین تسلا با بقیه ماشینا فرق داره همشون گازی هستن و تسلا برقی! پس نمیتونیم اون متد رو به همشون اعمال کنیم چون در این صورت یا همه باید برقی بشن یا همه از حمله تسلا باید با بنزین سوختشون تامین شه. نتیجه : اصل ABSTRACTION ، &quot;چگونه انجام شدن&quot; را مخفی و &quot;چه چیزی انجام شدن&quot; رو نمایش میده، پیچیدگی رو کم میکنه ، از تاثیرِ تغییراتِ متدها روی همه ی ابجکت ها جلوگیری میکنه.3. اصل سوم: INHERITANCE یا وراثتاصل وراثت رو که از قسمت اول هم باهاش آشنایی دارید، اینطوریه که میای یه ابجکت با کلی متد و پراپرتی میسازی و این متدهارو میتونی برای ابجکت های دیگه به ارث ببری و به اضافه چیزایی که به ارث بردی متدا و پراپرتی های مخصوص هر ابجکت رو بهشون اضافه کنی.به ارث بردن حرکت و توقف و... از یک ماشین توسط انواع مدل های ماشینتوی عکس بالا ما یه ابجکت ماشین داریم که توش پراپرتی های چرخ و آینه و در و متد هایی مثل حرکت و ترمز و بوق و... وجود داره و ما واسه ساخت انواع مختلف ماشین دیگه نمیایم دوباره از صفر چرخ رو اختراع کنیم یا چیزای دیگه رو، ما فقط میایم از ابجکت Car همه ی اینارو به ارث میبریم و چیزایی مثل رنگ و سرعت و... که برای هر ماشین فرق داره رو به هر ماشین اضافه میکنیم.مثالش توی کد:به ارث بردن متد start, stop و مشخص کردن سوخت منحصر بفرد برای هر ماشیندر مثال بالا ما یه ابجکت Car داریم که دارای متد هایی مثل حرکت و توقف هست و یه ابجکت تسلا داریم که این متد هارو به ارث برده تا ما دوباره نیاز نباشه از صفر بنویسیمشون و متد منحصر بفرد خودش ینی getPower هم داره که بهش سوخت منحصر بفرد خودشو میده  و حالا میتونیم مدل های مختلف تسلا رو با نمونه سازی از این ابجکت بسازیم و برای ولوو هم دقیقا همین پروسه اس.ما برای هیچ کدوم از این مدلا استارت رو تعریف نکردیم اما میبینیم که با صدا زدن استارت همشون میدونن چیکار باید بکنن چون به ارث بردنش.نتیجه: اصل INHERITANCE، از چند باره نویسیِ متد ها و اشغال حافظه جلوگیری میکنه ، پیچیدگی کد رو کمتر میکنه و متدهامون رو قابل استفاده مجدد میکنه.  4.اصل چهارم: POLYMORPHISM یا چند شکلی یا چند فرمیاصل آخر اینطوریه که اگه ما قراره از یه ابجکت متدهایی رو به ارث ببریم، متدهایی  که لازمه، تواناییِ بازنویسی  داشته باشن تا بدون تعریف کردن اون متد برای هر ابجکت و اشغال فضای بیشتر فقط خروجیش رو تغییر بدیم.و همچنین با از صفر نوشتن متد برای هر ابجکت علاوه بر اشغال فضای بیشتر ، پایین اومدن پرفورمنس و پیچیدگی و شلوغی یه اشکال دیگه هم داره اونم قابلیت نگهداری رو از بین میبره ینی شما اگه بخوای یه چیزی رو توی عملکرد این متد تغییر بدی باید توی همه ی این ابجکت ها اضافه کنی و حالا فرض کن بیشتر از هزارتا ابجکت داشته باشی که در اینصورت علاوه بر پرفورمنس به خاااره انگشتات هم یه سلامی میرسه :)مشترک بودن فرمون تو همه ماشین ها اما متفاوت بودن شکل و نرم بودنش توی هر ماشینتوی عکس بالا ما فرمون رو توی همه ی ماشین ها به ارث بردیم اما  تفاوتش توی هر ابجکت اون نرم بودن و شکل و قیافه اش هست مثلا فرمون پورشه و  پراید جفتشون فرمون دارند اما آیا این دو کاملا مشترک و شبیه به هم هستند؟ :)مثالش تو کد:همه ی ابجکت ها متد هایی با کارکرد های یکسان اما خروجی های متفاوت دارند.توی مثال بالا ما چندشکل مختلف از یک متد داریم و به این میگن polymorphism یا چند شکلی.نتیجه: اصل POLYMORPHISM، با بازنویسی یه متد و جلوگیری از دوباره نویسی یک متد برای چندین آبجکت، از اشغال بیشتر حافظه جلوگیری و باعث افزایش پرفورمنس، خوانایی کد و قابلیت نگه داری میشه و پیچیدگی رو کمتر میکنه.خب اینا چهار اصل یا ستون برنامه نویسی شی گرا بودن که بهشون پرداختیم اما ممکنه یه سری سوالا از جمله فرق اصل ABSTRACTION و ENCAPSULATION و یا فرق ABSTRACTION و INHERITANCE و... چیه و خب این قابل درکه چون همشون یه جورایی از کمک هم استفاده میکنن مثلا اصل POLYMORPHISM از اصل INHERITANCE استفاده میکنه تا پیاده بشه اینکه فرق اینا چیه هم ممکنه تو مصاحبه ها حتی پرسیده بشه و اما جواب اینه که مهم نیست که اینا شبیه هم هستن  و یه سری چیزای مشترک دارند چیزی که اینارو از هم متمایز میکنه روشِ هر اصل هست که از اون یکی متفاوته:روش encapsulation : جمع کردن دیتا های مرتبط داخلِ یک آبجکت برای غیر قابل دسترسی مستقیم کردنشون از محوطه ی بیرونیروش abstraction: پنهان کردن اینکه متد چجوری کار میکنه و نمایش دادن اینکه متد چیکار میکنه در جهت کم کردن از پیچیدگی کدهاروش inheritance : به ارث بردن متد ها در جهت قابل اسفاده مجدد کردن آنها و جلوگیری دوباره نویسی و اشغال فضای اضافهروش polymorphism: تغییر خروجی متدهای به ارث برده شده برای آبجکت های نمونه بدون نوشتن مجدد اون متد ها و بالا بردن قابلیت نگه داری و افزایش پرفورمنساگه از نتایج دقت کرده باشید همه ی اینا هدفی که توشون مشترک هست، کمتر کردن پیچیدگی با استفاده از پیاده کردن روش های منحصر به فرد خودشونه و این یعنی الگوی برنامه نویسی شی گرا. پیاده کردن ساده و قابل استفاده مجدد پروژه ها بر محور آبجکت ها.این مقاله اینجا به پایان میرسه و امیدوارم که برنامه نویسی شی گرا یا oop رو یک بار برای همیشه یاد گرفته باشید و تونسته باشم کمکی در جهت درک چگونگی این الگوی برنامه نویسی کرده باشم.خدانگهدار و موفق باشید ?</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Tue, 01 Feb 2022 19:59:51 +0330</pubDate>
            </item>
                    <item>
                <title>صفر تا صد oop در جاوااسکریپت! قسمت اول: prototype</title>
                <link>https://virgool.io/@samAghapour/sam-aghapour-oop1-prototype-mzzrkucfqgay</link>
                <description>سلام به جی اس کارای عزیز ?وقتی جاوااسکریپت یاد میگرفتم همیشه برام سوال بود که وقتی ما یه استرینج یا فانکشن یا ... هرچی تعریف میکنیم یه سری متد خاص برا خودشون دارن برای مثال وقتی یه متغیر با تایپ استرینج تعریف میکنیم میتونیم روش از متد search یا length و.. استفاده بکنیم ولی خب چطورر؟؟ وقتی دلیل این اتفاقا رو تو پشت پرده میبینیم تازه کم کم بخش بزرگی از مفاهیم oop در جاوااسکریپت هم برامون جا میفته و تازه میفهمیم چه خبره.پس من توی دو بخش جدا اول به پروتوتایپ ها و بعد به چهار مفهوم مهم توی oop با کلی مثال از دنیای کد و دنیای واقعی میپردازم تا یه بار برای همیشه یادشون بگیریم و از اونجایی که این مباحث هم توی مصاحبه ها هم توی پروژه ها و موقعیت های مختلف خیلی مهمن دیگه نگرانی بابتشون نداشته باشیم. مفهوم __proto__ و prototypeجاوااسکریپت یه زبان بر پایه آبجکت و پروتوتایپ هستش  و برخلاف خیلی از زبان ها بر پایه کلاس نیستش، همین قضیه باعث شده یکم بحث چگونگی ساخته شدن سلسله آبجکت ها و وراثت از هم دیگه یکم پیچیده و عجیب غریب به نظر بیاد. خب اما اصلا پروتوتایپ چی هست؟؟! بزارید با یه مثال شروع کنیمتوی عکس بالا ما یه آبجکت ساده ساختیم و سه تا از پراپرتی هاشو صدا زدیم، امااا ما فقط name و age رو تعریف کردیم! پس متدِ hasOwnProperty از کجا اومد؟ (به پراپرتی آبجکت که تایپ فانکشن هستش میگن متد) ما که همچین چیزی تعریف نکردیم ? هوممم.. چطوره بیایم و کل آبجکت رو کنسول لاگ بگیریم ببینیم چیا داره داخلش داره.console.log(myobject)خب خب اینجاس که میفهمیم جاوااسکریپت یه چیزیو خودش به صورت پیش فرض هر دفعه که یه آبجکت میسازیم میزاره توش و اون چیزی نیست جز __proto__ خب حالا بیاید ایندفعه این پرارپتی پنهان رو لاگ بگیریم و بازش کنیم ببینیم چیا داره؟console.log(myobject.__proto__)اینجاس که  متد hasOwnProperty و همینطور کلی متد جالب دیگه پیدا میکنیم و جالبیش اینجاس که اگه ما هزار تا هم آبجکت بسازیم قراره همشون این متدا و به بیان دیگه این آبجکت پروتو که global object prototype هم گفته میشه و شامل کلی متد هستش رو داشته باشن و جالب ترش اینه که قرار نیست برای هر ابجکت یه دونه از این ابجکتا ساخته شه و پدر حافظه رو در بیاره! بلکه همشون از یه آبجکت که این متدا رو داره به ارث میبرن و همشون از یه ابجکت استفاده میکنن و اخرین نکته جالبی که تو عکس بالا میبینیم اینه که حتی این آبجکت که خودش پپروتو هستش هم یه پراپرتی پروتو دیگه داره که به بن بست رسیده و مقدارش null هستش ولی اصل مسله همینه که هرابجکتی یه پروتو داره حتی خود ابجکت پروتوتایپ. کلا جالبیت از سر و روی جاوااسکریپت میباره :)بریم به چند روش مختلف موشکافی کنیم ای پروتو خان رو :با استفاده از Object literal و متد های object.create و object.setPrototypeOf1.استفاده از متد object.create**object.create()خب توی مثال بالا ما یه آبجکت car با سه تا پراپرتی با تایپ فانکشن یا متد داریم و نه هیچ چیز دیگهحالا وقتی میایم از object.create استفاده میکنیم چه اتفاقی میفته؟ ما پارامتر اول رو برابر با car قرار دادیم و پارامتر دوم یه ابجکت که پراپرتی name داره و مقدارش tesla هست ( داخل این متد به پراپرتی ابجکت به همین شکل مقدار داده میشه در غیر اینصورت نیازی نبود پراپرتی برابر با یه ابجکت دیگه که مقدار value داره باشه خلاصه زیاد درگیر اون قسمت نشید) پس متغیر tesla برابر با چی میشه ؟ بیاید ببینیمconsole.log(tesla)خب پس با توجه به عکس بالا میبینیم که با object.create ما میایم با استفاده از پارامتر دوم ابجکتی که میخوایم رو با پراپرتی های اختصاصی خودش میسازیم و پروتو ی این ابجکت رو با استفاده از پارامتر اول از ابجکت دیگه ای ( که توی این مثالcar هستش) کپی میکنه و اینطوری میشه که پروتو برابر میشه با پراپرتی های داخل ابجکت car و یه جورایی به ارث میبره اون پراپرتی هارو و اما این ابجکت به ارث برده شده هم خودش همونطور که بالاتر گفتیم یه پروتو داره و این پروتو به global object protoype میرسه.زنجیره پروتوتایپ یا object prototype chainingکلا یادتون باشه این پروتوتایپ ها مثل زنجیره به هم وصل هستن و هر چقدر هم این پروتو متصل باشه به یه ابجکت دیگه در آخر میخوره به global object prototype و بعد از اخرین پروتو میخوره به null به این قضیه میگن prototype chaining یا زنجیره پروتوتایپ.خیله خب حالا ما دوتا متغیر دیگه هم داریم که یکی یکی بررسی میکنیم، متغیر detail رو اول چک میکنیم که برابر با یه ابجکت با پراپرتی اختصاصی speed هستش با مقدار 3001 و پروتوی این ابجکت رفرنس داده شه به متغیر tesla و تسلا هم همونطور که بالاتر دیدیم پروتوش رفرنس داده شده به car پس فک کنم میدونیم قراره چی باشه نتیجه :console.log(details)و بله به این میگن زنجیره پروتوتایپ: متغیر detail یه پراپرتی داره اما از طریق پروتوش پراپرتی name از تسلا و از طریق پروتوی تسلا به متدای sayname , start , stop از ابجکت car و از طریق پروتوی car به تموم متدای ابجکت گلوبال دسترسی داره.حالا Prototypal delegation چیه؟اگه دقت کنید توی مثالای بالا پروتوتایپ ها از پایین به بالا وصلن ، ینی چی ؟ ینی اینکه متغیر detail به پراپرتی name توی تسلا دسترسی داره چون پروتوش به تسلا وصله اما تسلا به پراپرتی speed توی detail دسترسی نداره چون پروتوش به detail وصل نیست و به یه چی دیگه وصله ،به این قضیه میگن Prototypal delegation. پس ینی اگه الان مثلا لاگ بگیریم console.log(tesla.speed) مقدار رو اول توی خود ابجکت میگرده و وقتی پیداش نکنه میره سراغ پروتوتایپش که car هستش و وقتی اونجا پیداش نکنه میره سراغ پروتوتایپ car که همون  global object prototype  هست و اونجا هم چیزی به اسم speed پیدا نمیکنه و میره سراغ پروتوی بعدی و میبینه که اوپس این پروتو دیگه بن بسته و null هستش و در نتیجه undefined برمیگردونه دلیل ارور خیلی رو مخی به اسم is not a functionبا توجه به چیزی که بالاتر گفتم، جاوااسکریپت وقتی یه پراپرتی رو توی زنجیره پروتو تایپ پیدا نکنه اندیفایند برمیگردونه حالا اگه speed بجای استرینج یه فانکشن یا همون متد بود در صورت پیدا نکردن متد بهمون ارور میداد که tesla.speed is not a function  پس الان میدونیم که چی میشه به همچین خطایی میخوریم مثلا بعضی وقتا شده روی آرایه یا هر تایپ دیگه ای یه متدی استفاده کنیم که به این ارور بخوریم اون بخاطر اینه که همچین متدی توی زنجیره پروتوتایپیه اون تایپ متغیر وجود ندارهبریم سراغ سومین متغیر که volvo باشه ، خب این متغیر دقیقا مثل متغیر تسلا نوشته شده و قراره پراپرتی اختصاصی خودش با مقدار اختصاصیش رو داشته باشه و پروتوش به car رفرنس داده بشه و وقتی لاگ بگیریم نتیجه اینطوریه:console.log(volvo)2.استفاده از متد object.setPrototypeOf **سه تا متغیری که بالا تر ساختیم رو میتونیم با متد object.setPrototypeOf  به شکل زیر هم بنویسیم:object.setPrototypeOf()توی عکس بالا ما هر متغیر رو برابر با ابجکت با پراپرتی های اختصاصی خودش و مقدار اختصاصی خودش قرار میدیم و پایینش با استفاده از متد object.setPrototypeOf میایم از طریق پارامتر اول ابجکتی که میخوایم بهش پروتوتایپ خاصی بدیم رو انتخاب میکنیم و از طریق پارامتر دوم پروتوی اون ابجکت رو رفرنس میدیم به یه ابجکت دیگه، نتایج رو اگه لاگ بگیریم دقیقا همون نتایجیه که بالاتر دیدیم.با استفاده از constructor function و کلمه کلیدی newconstructor functionفانکشن هم functoin است هم object!فانکشن ها توی جاوااسکریپت مثل آبجکت میتونند رفتار کنند همونطور که تو عکس بالا هم میبینید میتونن پراپرتی بگیرن و وقتی تعریف میشن جاوااسکریپت به صورت پیشفرض کلی متد و پراپرتی بهشون اضافه میکنه ، حالا بیاید عکس بالا رو موشکافی کنیم:وقتی یه فانکشن داخلش از this.** استفاده شده و اسم این فانکشن هم به صورت capitalize (حرف اول بزرگ) است و اینطوری داریم میگیم که این فانکشن در اصل یه آبجکت هستش و میشه ازش نمونه سازی کرد و وسیله ای که باهاش نمونه سازی میکنیم هم همون کلمه کلیدی new هستش. درواقع داخل فانکشن وقتی از this استفاده میکنیم داریم میگیم که جاوااسکریپت عزیز هر وقت یه نمونه از این فانکشن ساخته شد پراپرتی فلان رو (که توی این مثال name) هستش بده به این نمونه و مقدارشم برابر با پارامتر فلان (تو این مثال name) بکن. پس وقتی یه متغیر tesla مینویسیم که که با new از Car نمونه میسازه درواقع انگار داریم یه ابجکت میسازیم که پراپرتی name برابر با tesla داره و برای volvo هم همینطور. به این نوع فانکشن ها ( که تو این مثال Car هستش) ، constructor function گفته میشه.حالا یه چیزی که این وسط هست اون پروتوتایپ ها هستن! ما در واقع طبق عکس بالا به آبجکت Car یه سری متد ها به پروتوتایپش اضافه میکنیم و وقتی یه نمونه از این ابجکتمون رو مثلا با اسم تسلا میسازیم و تسلا رو لاگ میگیریم این میشه نتیجش:console.log(tesla)خب ما از نتیجه میتونیم اینو بفهمیم که وقتی یه نمونه ساختیم در اصل یه آبجکت ساختیم با پراپرتی name  که مقدارشم قرار دادیم با tesla حالا اون متدهایی که به پروتوتایپ ابجکتِ Car داده بودیم همشون جمع شدن و به طور یه ابجکت داده شدن به پروتوتایپه هر نمونه ای که از car ساخته میشه و پروتوی ابجکت متدهای اختصاصیمون هم رفرنس میخوره به global object prototype طبق معمول. برای volvo هم دقیقا همین پروسه انجام میشه.کلمه new توی عکس بالا:یه ابجکت میسازه با پراپرتی هایی که توی Car هست و this رو رفرنس میده به ابجکت جدیدی که ساختهپروتوی این ابجکت رو رفرنس میده به پروتوتایپ Car و حالا میرسیم به نکته جالبش که ما کاربرد اصلی پروتوتایپ رو هم نشون میده :ما اگه بخوایم مثلا صدتا متغیر تعریف کنیم که همشون متدهای start , stop و... داشته باشن که عملکرد همه ی این متدها هم یکیه بنظرتون منطقیه که بیایم همه ی این آبجکت هارو یکی یکی تعریف کنیم و برای هرکدوم همه ی این فانکشن هارو یکی یکی جدا جدا تعریف کنیم؟ خب معلومه که نه!! اینطوری که خااارِ حافظه تار و مار میشه پس میایم مثل روش بالا یه constructor function مینویسیم و میگیم که هرکی خواست یه نمونه از این فانکشن بسازه نیازی نیست هزار بار پراپرتی اسم رو تعریف کنه من تعریفش میکنم و نمونه ها فقط مقدارشو بدن و علاوه بر اون نیازی نیست تک تک این متد هارو براشون بنویسی من توی پروتوتایپم تعریفشون میکنم و هر نمونه ای که ازم ساخته شد اینارو به ارث ببره و از همین جا استفاده کنه و این یعنی جلوگیری از نوشته شدن تکراریه هزاران متد و پراپرتی و نجاتِ حافظه و پرفورمنس حالا بیاید نتیجه چیزی که گفتیم رو تو عکس زیر ببینیم:new Car(&#039;name&#039;)خب طبق عکس بالا teslaو volvo با اینکه هیچوقت متد های استارت و استاپ و .. براشون به صورت جدا جدا نوشته نشد هر دوشون دسترسی دارن به این متدها و یه چیزه دیگه اینکه اگه اخری رو ببینید اومدم noneFunction رو صدا زدم و اینو چون نه من توی پروتوتایپ تعریف کردم و نه توی global object prototype همچین چیزی هست هر ابجکتی رو توی زنجیره پروتوتایپ ها گشته پیدا نکرده و در آخر این ارور رو برگردونده.و بله جاوااسکریپت برای ابجکتای خودشم یه global object prototype ساخته تا همشون از همین به ارث ببرن وگرنه که دیگه میترکید بخواد برای هر ابجکتی که تو پروژه نوشته میشه کل اون متدهارو تعریف کنه!فرق __proto__ و prototype ؟خب شاید این سوال براتون یپش بیاد که فرق این دو چیه؟وقتی یه فانکشن تعریف میکنیم پراپرتی prototype  براش ساخته میشه تا وقتی میخوایم از روش چند تا ابجکت نمونه سازی کنیم این proto داخل ابجکت نمونه اشاره کنه به prototype فانکشن که یه ابجکته شامل متدایی که ما بهش اضافه کردیم (توی مثال بالا میشه ابجکتی که توش start , stop , sayName رو اضافه کردیم).prototype vs __proto__پس prototype فقط پراپرتیِ فانکشن هستش و توی ابجکت همچین اسمی برای پراپرتی وجود نداره و در عوض توی ابجکت __proto__ داریم.با استفاده از class و کلمه کلیدی newخب کم کم داریم وارد محوله oop میشیم دیگه...، ما توی زبونای برنامه نویسی مختلف مبحثی داریم به اسم oop که طراحی و پیاده سازی برنامه بر محور ابجکت ها و کلاس هاس که حالا واردش نمیشم و کلاس ها چیزی بود که جااوااسکریپت توی es6 معرفی کرد و کاری کرد که oop توی جاوااسکریپت هم ممکن بشه اما به شیوه خودش! ینی اینکه ظاهر رو با استفاده از کلاس مثل oop توی بقیه زبان های برنامه نویسی در آورد اما پشت پرده دقیقا همین پروسه ی prototype رو پیاده میکنه درحالی که زبونای دیگه اصلا پشت پردشون اینطوری نیست!حالا پروسه هایی که با روش های constructor function و object literal رفتیم رو با این روش و سینتکس جدید پیاده میکنیم تا هم ببینیم ظاهر oop چجوریه هم ببینیم این پروسه ارث بری و پروتوتایپ با کلاس ها چه شکلیه.ES6 classتوی عکس بالا کلاس car رو تعریف کردیم و constructor که داخلش نوشتیم و پراپرتی name رو هم مشخص کردیم این constructor دقیقا برابر با همون فانکشنیه که توی constructor function پیاده کردیم ینی این:constructor function === class constructor functionو متدهایی که داخل کلاس نوشتیم دقیقا مثل اینه که به پروتوتایپ constructor function متد بدیم ینی این:prototype defining in class and constructor functionحالا بیاید این قسمتارو توضیح بدیم: نمونه سازی instantiateخب آشنا هستیم که new دقیقا چیکار میکنه :میاد یه نمونه ابجکت از کلاس car میسازه با پراپرتی اسم و یه پروتو که رفرنس داده میشه به پروتوتایپی که داخلش سه تا متد start , stop , sayName هست و پروتوی درون اون هم به آبجکت پروتوتایپ... بعدش اومدیم یه کلاس دیگه ساختیم به اسم Detail و پراپرتی اختصاصی خودش به اسم speed رو تعریف کردیم و با extends  و super پروتوتایپش رفرنس داده شده به ابجکت Car با پراپرتی name و سه تا متد، و در آخر پروتوی این ابجکت هم رفرنس داده میشه به ابجکت پروتوتایپ گلوبال. اگه متغیر detail رو که از Detail نمونه سازی کردیم لاگ بگیریم نشون میده این قضیه رو:&#039;console.log(detail)&#039;خب  جاوااسکریپت اومده اینطوری oop رو ظاهر سازی کرده ولی پشت پرده مثل بقیه oop ها عمل نمیکنه و همون روش پروتوتایپ خودشو پیش میگیره :)مبحث پروتوتایپ با انواع و اقسام روش ها رو یاد گرفتیم توی قسمت دوم میریم که تموم مفاهیم oop رو یاد بگیریم و بتونیم ازش تو پروژه ها استفاده کنیم و تو مصاحبه ها از پس سوالاش بر بیایم و کلا یه وجب دیگه توی javascript و کلا برنامه نویسی عمیق تر شیم.پس تا قسمت بعد خدانگهدار?</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Thu, 27 Jan 2022 00:50:44 +0330</pubDate>
            </item>
                    <item>
                <title>یادگیری hoisting , scopes , closures در جاوا اسکریپت</title>
                <link>https://virgool.io/@samAghapour/sam-aghapour-scopes-closures-hoisting-vc46skapavc5</link>
                <description>سلام به جی اس کارای عزیز ?توی جاوا اسکریپت یه سری مباحث اولیه اما خیلی مهم هستن که یادگیریشون برای هر جی اس دولوپری واجبه که امروز قراره چندتا از اون مباحث شاملِ scopes , closures , hoisting رو زیر و رو کنیم و ببینیم چی هستن و چیکار میکنن و به چه دردی میخورن اما این زیر و رو کردن رو سعی میکنم به ساده ترین و کوتاه ترین شکل ممکن انجام بدم که نه گیج بشید نه حوصلتون سر بره..1. بحث Scopes **اسکوپ یا محدوده ینی چی؟اسکوپ، محدوده ای هستش که یه متغیر یا فانکشن یا ابجکت در دسترس و قابل استفاده هستش به همین سادگیاسکوپ ها در جاوااسکریپت ؟توی جاوااسکریپت دو نوع اسکوپ داریم:محدوده جهانی یا Global Scopeمحدوده محلی یا Local Scopeمتغیر هایی که داخل فانکشن ساخته میشن داخلِ local scope هستن  و متغیر هایی که خارج از فانکشن ها ساخته میشن داخلِ global scope هستنمحدوده جهانی یا Global Scopeوقتی شروع به ساختن یه متغیر توی فایل جاوااسکریپت میکنی که داخل هیچ فانکشنی نیست شما این فانکشن رو داخل محدوده Global نوشتی و میتونی هر جایی حتی داخل local scope ها (داخل فانکشن ها) بهشون دسترسی داشته باشی :var someThing = &#039;sam&#039; console.log(someThing);   //output: &#039;sam&#039; 
function callSomeThing () {
console.log(someThing);   //output: &#039;sam&#039;
//متغیری که تو محدوده جهانی نوشتیم اینجا هم در دسترس هستش
}محدوده محلی یا Local Scopeمتغیر هایی که داخل فانکشن ها تعریف میکنیم داخل محدوده محلی یا local scope هستن و محدود به محدوده همون فانکشن هستن و نه هیچ جای دیگه(ینی نه داخل فانکشن های دیگه و نه داخل محدوده جهانی ، که البته یه استثنای کوچیکی هست که تو جلوتر بهش میرسیم)//Global Scope
function someFunc() {
// Local scope 1 اولین محدوده محلی 
      functoin someOtherFun(){
 //local scope 2 دومین محدوده محلی   }
}

function thirdFunc(){
//local scope 3 سومین محدوده محلی
}منطقه محدود Block statementاین وسط لازم به ذکره که محدوده های حلقه های for , while و یا محدوده های if , switch برخلاف فانکشن ها محدوده خاص محلی ندارن و از محدوده جایی که توش هستند استفاده میکنن، ینی چی؟ ینی اینکه اگه یه شرط یا حلقه توی global scope نوشته شده باشه متغیرای داخلشم توی global scope به حساب میان و همه جا در دسترس اند. مثل:if(condition){
// global scope  این شرط در محدوده جهانی نوشته شده 
var someThing = &#039;sam&#039;; // this is still in global scope
}
console.log(someThing);   //output : &#039;sam&#039;توی ES6 ، دو نوع متغیر جدید به اسم های let , const معرفی شدند که یه فرقایی نسبت به var دارند و یکی از اون فرق ها همینجا خودشو نشون میده اونم اینه که let و const برخلاف var وقتی داخل محدوده حلقه یا شرط استفاده بشن اون متغیر داخل همون محدوده قابل استفاده است و نه خارج از اون! مثل:if(condition){

// someThing is in the global scope because of the &#039;var&#039; keyword
var someThing = &#039;sam&#039; ;   

// secondThing is in the local scope because of the &#039;let&#039; keyword
let secondThing = &#039;javaScript is great!&#039; ;  

// thirdThing is in the local scope because of the &#039;let&#039; keyword
const thirdThing= 2022  ; 
}
console.log(someThing);   //output : &#039;sam&#039;
console.log(secondThing);   //output : Uncaught ReferenceError: secondThing is not defined
console.log(thirdThing);   //output : Uncaught ReferenceError: thirdThing is not defined بحث Lexical scopeبالاتر گفتم که &quot; متغیر هایی که داخل فانکشن ها تعریف میکنیم داخل local scope هستن و محدود به محدوده همون فانکشن هستن و نه هیچ جای دیگه که البته یه استثنای کوچیکی هست که تو جلوتر بهش میرسیم)&quot;خب اینجا همونجاییه که باید بگم موقع استفاده از متغیر داخل فانکشن یا local scope بحثی وجود داره به اسم lexical scope ( بعضیا static scope هم میگن بهش). حالا این ینی چی؟این موضوع تو خیلی از زبونای برنامه نویسی وجود داره و اگه خیلی ساده بخوام بگم به این معنیه که اگه ما یه فانکشن داخل یه فانکشن دیگه داشته باشیم میتونیم به متغیرای محدوده ی محلیِ فانکشن پدرش دسترسی داشته باشه و به بیان دیگه هرچند تا فانکشن تو در تو داشته باشیم فانشکن فرزند علاوه بر متغیرای محدوده خودش به متغیرای محدوده پدرش و پدرِ پدرش و... دسترسی داره البته این رو در نظر بگیرید که این رابطه از بالا به پایینه و بر خلاف فانکشن فرزند ، فانکشن پدر نمیتونه به متغیرای محدوده فانکشن فرزند دسترسی داشته باشه! مثالش:lexical scopeتوی عکس بالا همونطور که از کامنتا مشخصه فانکشن بالاتر نمیتونه به متغیرای فانکشنای داخلش دسترسی داشته باشه اما فانکشن های فرزند میتونن به متغیرای فانکشنی که توش هستن دسترسی داشته باشن.بحث dynamic scopeحالا که بحث static scope رو گفتیم بزارید یه نگاه کوچیکی هم داشته باشیم به dynamic scope تا کاملش کنیم. مثال زیر رو نگاه کنید تا فرق بین dynamic scope و lexical scope رو متوجه شیم.lexical scope vs dynamic scopeتوی بحث lexical scope اگه کد بالارو اجرا کنیم وقتی فانکشن b صدا زده میشه داخلش فانکشن a اجرا شده و فانکشن a داخلش someVar رو لاگ کرده خب وقتی توی a هیچ متغیری با اسم someVar نداریم بخاطر lexical بودن میاد اون محدوده ای که این فانکشن توش تعریف شده رو میگرده (پرنتش) تا ببینه میتونه این متغیر رو اونجا پیدا کنه و بله! متغیر someVar توی محدوده ای که فانکشن a تعریف شده وجود داره و برابر با 0 هستش پس خروجی نهایی 0 هستش.حالا اگه بحث dynamic scope رو در نظر بگیریم توی کد بالا فانکشن a وقتی میبینه متغیر someVar وجود نداره بجای محدوده ی جایی که توش تعریف شده میره محدوده ای که توش &quot;صدا زده شده&quot; رو میگرده ینی محدوده محلیِ فانکشن b که متغیر someVar برابر با 1 هستش و خروجی نهایی 1 هستش.نتیجه نهایی از مقایسه:توی lexical scope توی محدوده ای دنبال متغیر میگرده که فانکشن توش تعریف شدهتوی dynamic scope توی محدوده ای دنبال متغیر میگرده که فانکشن توش صدا زده شدهبحث scopes اینحا تموم میشه و حالا میریم سراغ closure2. بحث closures **قابلیت closure توی جاوااسکریپت این امکان رو به فانکشن های داخل یا فانکشن دیگه میده که بتونه به متغیرای محدوده فانکشنی که توش تعریف شده دسترسی داشته باشه که تاالان با این قضیه تا حدی آشنا شدیم اما کاربرد و جالبیش هنوز مونده!پس closure یه فانکشن داخلی هستش که به سه تا متغیرای سه نوع محدوده (scope-chain)دسترسی داره : محدوده خودشمحدوده فانکشن هایی که توش ساخته شدهمحدوده جهانی یا global scope function outer() {
 var b = 50;
function inner() {
 var a = 30; 
         console.log(a+b);
    }
return inner
}

let x = outer();خب توی کد بالا میتونید حدس بزنید closure ما کدومه؟درسته! inner فانکشن closure ما هستش که داخل یه فانکشن outer صدا زده شده و به مقدار b داخل محدوده outer هم دسترسی دارهیه چیزی رو به خاطر داشته باشید که متغیرای داخل یه فانکشن تا زمانی وجود دارن که اون فانکشن داره اجرا میشه و به محض اینکه فانکشن اجرا و تموم بشه اون متغیر داخلش دیگه وجود نداره تا زمانی که دوباره فانکشن صدا زده بشه و اجرا شه  حالا با توجه به این توضیحات بیاین این کد بالارو کامل قدم به قدم کالبد شکافی کنیمفانکشن outer شامل یه متغیر b با مقدار 50 هستش و در آخر داره فانکشن inner رو برمیگردونه دقت داشته باشید که داره خود فانکشن رو برمیگردونه نه مقادیر داخل فانکشن inner رو چون inner رو بدون پرانتز برگردوندهپس وقتی ما متغیرx رو برابر با ()outer قرار بدیم x برابر میشه با فانکشن inner و الان x یه فانکشن هستx = function inner () {
     var a = 30; 
         console.log(a+b); 
}4. فانکشنouter وقتی ریختیمش تویx اجرا شد و تموم شد و حالا مقدار b دیگه وجود نداره! پس وقتی x رو صدا بزنیم دقیقا b رو از کجا میاره که با متغیرa  جمع بزنه و نمایش بده ؟؟5. اینجاست که داستان جالب میشه! جاوااسکریپت متغیر a رو میبینه که برابر با 30 هستش و اوکیه و وقتی میاد میرسه به console.log میبینه یه b هم اینجا هستش! حالا تنهاقابلیتی که اینجا به داد جاوااسکریپت میرسه چیه؟؟؟ آفرین closure6. فانکشن inner میره سراغ محدوده فانکشنی که توش ساخته شده و اونجا دنبال b  میگرده و پیداش میکنه و درنتیجه وقتی x رو اجرا کنیم a و b رو جمع میزنه و 80 رو نمایش میدهبیاین برای اینکه مطمعن شیم این مبحث رو دونستیم و کاربرد اصلیو فهمیدیم یه مثال کاربردی تر دیگه رو قدم به قدم کالبدشکافی کنیم:function NumberFunc() {
let i = 0;
function incrementNumberFunc() {
let b = 10
console.log(`i = ${i++} , b = ${b++}`);
}
return incrementNumberFunc
}
let x = NumberFunc();
let y = NumberFunc();

x(); //output: ??
x(); //output: ??
x(); //output: ??
y();//output: ??1.مقدار x رو برابر با NumberFunc میزاریم و این فانکشن برای اولین بار اجرا میشه ، متغیر i ساخته میشه با مقدار 0 بعدش فانکشن incrementNumberFunc توی x ذخیره میشه با اینکه اینجا کار فانکشن NumberFunc تمومه و متغیر i هم نابود میشه  اما مقدار i توی closure وجود داره و وقتی x اولین بار اجرا میشه فانکشن incrementNumberFunc اجرا میشه  متغیر b ساخته میشه با مقدار 10 ، حالا مقدار  0 رو از i ای که داره نشون میده و 10 رو هم از b میگیره و نشون میده و حالا که کار فانکشن تموم شد دیگه متغیر b نابود میشه این پروسه توی متغیرy هم انجام شده و بعد از اجرا همین نتیجه رو برمیگردونه2. بار دوم که x صدا زده میشه همین پروسه دوباره تکرار میشه اما ایندفعه متغیر i رو که از کلاژر گرفتیم و از پروسه قبلی  مقدارش ++ شده و مقدار 1 رو نشون میده ولی دیگه b ذخیره نشده و از نو ساخته میشه و همون 10 رو نشون میده3. بار سوم که x اجرا میشه بازم همین پروسه اجرا میشه و مقدار 2 برای i و 10برای b رو نشون میده4. حالا y که اجرا بشه چون موقع تعریف کردنش i مساوی با 0 ذخیره شده پس این اولین باره اجرای y هستش و مثل اولین اجرای x هستش و مقدار 0 رو برای i  و 10 برای b  نشون میده پس در نتیجه اینطوری میشه:x(); //output : i = 0 , b = 10
x(); //output : i = 1 , b = 10
x(); //output : i = 2 , b = 10
y(); //output : i = 0 , b = 10پس closure ترکیبی از فانکشن و قابلیت به یاد سپردن متغیر های درون محدوده خارجیش هستش.3. بحث Hoisting **خب hoisting یه مکانیزم توی جاوااسکریپت هستش که وقتی میایم متغیر یا فانکشن یا کلاسی چیزی تعریف میکنیم قبل از اجرا اون رو میاره و بالای محدوده اش قرار میده به بیان دیگه مهم نیست کجا بیای فلان متغیر رو تعریف کنی، جاوااسکریپت برش میداره و میبره بالای محدوده اش میزاره .البته باید اینو به بگم که جاوااسکریپت فقط اسم متغیر رو با مقدار پیش فرض undefined میبره بالا میزاره  و مقداری که ما به متغیر دادیم سر جای خودش میمونهتوی جاوااسکریپت وقتی میخوایم یه متغیر تعریف کنیم سه تا مرحله در پیش رو داره:1.  اعلام کردن یا declaration مثل:let a ;2. مقداردهی کردن یا initialisation /assignment مثل:a = &#039;sam&#039;3. استفاده کردن یا usage مثل: console.log(a + &#039;is developer&#039;);ما معمولا این مراحل رو توی یه خط پیش میبریم به این صورت :let a = &#039;sam&#039;اما ما هرچی هم اینطوری بنویسیم جاوااسکریپت پشت پرده به همون روش خودش تیکه تیکه مراحل رو پیش میبره ینی اول میبره بالای محدوده و declare میکنه و بعدش مقداردهی یا assignment انجام میده ،حالا این بالا بردن یا hoisting  هم باید بگم که قبل از اجرا شدن هر کدی اتفاق میفته .یه نکته دیگه ای که باید به یاد داشته باشین اینه که اگه یه مقداری رو به متغیری بدین که اصلا declare یا اعلام نشده جاوااسکریپت خودش میاد توی محدوده global یه متغیر با اون اسم اعلام میکنه :) مثال:حالا که میدونیم جاوااسکریپت چطور این قضیه رو هندل میکنه بهتره که به خاطر داشته باشین تا همیشه متغیر رو تعریف و بعد مقداردهی کنید.حالا بیاید جلو وپشت پرده hoisting رو چند تا مثال ببینیم:در محدوده جهانی یا global scopeچیزی که ما میبینیم:console.log(hoistedVar);   //output : undefined
var hoistedVar = &#039;some random value&#039;چیزی که جاوااسکریپت اجرا میکنه:var hoistedVar;
console.log(hoistedVar) //output: undefined
hoistedVar = &#039;some random value&#039;در محدوده محلی یا local scopeچیزی که ما میبینیم:function hoist() {
  console.log(message); 
  var message=&#039;Hoisting is all the rage!&#039;
}

hoist();// output: undefinedچیزی که جاوااسکریپت اجرا میکنه:function hoist() {  
var message;
 console.log(message);  
 message=&#039;Hoisting is all the rage!&#039;
 } 
 hoist();// output: undefined فک نمیکنم مثالای بالا نیاز به توضیح بیشتر داشته باشه پس با توجه به این مثالا پیشنهاد میشه که همیشه قبل از اجرا متغیر رو تعریف و مقداردهی کنیماز وقتی let و const در es6 معرفی شدند یکی دیگه از تفاوت های این دو با var این هست که اینجور مواقع مچ جاوااسریکپترو میگیره بجای اینکه مقدار آندیفایند رو بهت برگردونه رسما بهت ارور میده که آقا یا خانم تو هنوز اینو مقداردهی نکردی پس حق نداری ازش استفاده کنی مثال:console.log(hoistedVar);   //Output: ReferenceError: hoist is not defined ...
let hoistedVar = &#039;some random value&#039;البته اینو باید بدونید که اگه دستی بیاید با let یا const یع متغیر تعریف کنید ولی بهش مقدار ندید و قبل مقدار دادن استفاده کنید دیگه ارور رو نمیده و همون آندیفایند رو میده مثال:let hoistedVar;

console.log(hoistedVar); // Output: undefined
hoistedVar= &#039;some random value&#039;حالا برای فانکشن و کلاس هم چندتا مثال بزنیم تا تکمیل شه این بحث...فانکشن هادو نوع فانکشن میتونیم توی جاوااسکریپت بنویسیم:1. نوع اول : Function declarations که به اینصورت نوشته میشه:function someFunc(){ 
//code
 }2. نوع دوم : Function expressions که به اینصورت نوشته میشه:var someFunc = function(){  
//code  
}نوع اول  Function declarations :توی این نوع فانکشن  جاوااسکریپت به طور کامل فانکشن رو برمیداره میاره میزاره بالای محدوده اش، واسه همینم هست که میتونیم فانکشن رو تو خط های بالاتر از محل تعریفش صدا بزنیم و استفاده کنیم مثال:someFunc(); // output: &#039;hi&#039;

function someFunc(){  
console.log(&#039;hi&#039;)
 }نوع دوم Function expressions :توی این نوع فانکشن جاوااسکریپت فقط اسم رو میبره بالا و طبق روال ثابت بهش مقدار undefined میده و وقتی بخوایم استفاده کنیم بهمون ارور &quot;TypeError: expression is not a function&quot;میده چون داریم آندیفایند رو به عنوان فانکشن صدا میزنیم مثال:someFunc(); // output: TypeError: expression is not a function
var someFunc = function(){ 
  console.log(&#039;hi&#039;) 
 }کلاس هامثل فانکشن ها ، دو نوع کلاس میتونیم توی جاوااسکریپت بنویسیم:1. نوع اول : Class declarations که به اینصورت نوشته میشه:class SomeClass {
  constructor(name, lasname) {
    this.name= name;
    this.lastname= lastname;
  }
}2. نوع دوم : class expressions که به اینصورت نوشته میشه:var someClass = class {   
  constructor(name, lasname) { 
    this.name= name;    
    this.lastname= lastname;  
 } 
}نوع اول  class declarations :توی این نوع کلاس  جاوااسکریپت hoist نمیکنه و اگه قبل مقداردهی از کلاس استفاده کنیم ارور میده:var user = new SomeClass();
user.name= &#039;sam&#039;;
user.lastname= &#039;aghapour&#039;;

console.log(user); // Output: ReferenceError: SomeClass is not defined

class SomeClass {  
 constructor(name, lasname) { 
    this.name= name;   
    this.lastname= lastname;   
 } 
}نوع دوم class expressions :توی این نوع کلاس دقیقا مثل این نوعِ فانکشن، جاوااسکریپت فقط اسم رو میبره بالا و طبق روال ثابت بهش مقدار undefined میده و موقع استفاده ارور میده. مثال:var user = new SomeClass();
 user.name= &#039;sam&#039;;
 user.lastname= &#039;aghapour&#039;;
console.log(user); // Output: TypeError: SomeClass is not a constructor

var SomeClass = class {
 constructor(name, lasname) { 
     this.name= name;    
     this.lastname= lastname;
  }
}; خیله خب این مقاله اینجا به پایان میرسه ، خسته نباشی و امیدوارم که یه چیزی یادگرفته و یه قدم دیگه تو اقیانوس بیکران جاوااسکریپت عمیق تر شده باشی :)خدانگهدار و موفق باشی ?</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Sat, 15 Jan 2022 02:59:41 +0330</pubDate>
            </item>
                    <item>
                <title>یادگیری redux، ساده تر از چیزی که فکرش رو میکنی!</title>
                <link>https://virgool.io/@samAghapour/sam-aghapour-redux-yunzd2ulqjyc</link>
                <description> https://vrgl.ir/rBeFh ما برای استفاده از دیتا توی کامپوننت ها از props استفاده میکنیم تا بتونیم دیتا رو به کامپوننت ها پاس بدیماما وقتی تعداد کامپوننت های تو در تو زیاد بشه استفاده از این روش اصلا پیشنهاد نمیشه و به این شلوغ کاری به اصطلاح prop drilling گفته میشه مثل عکس پایین:توی عکس بالا ما برای اینکه دیتارو توی فایل textContent استفاده کنیم باید اون دیتارو از تمام پرنت هاش عبور بدیم تا به این برسهراه حلی که برای این مشکل هست global state management هست که به روش های گوناگون و با ابزار های مختلف میشه پیادش کرد از جمله context api و redux که ما توی این مقاله قراره راجب redux صحبت کنیم  ریداکس یه کتابخونه برای مدیریت کردن استیت های گلوبال هستش که توی کتابخونه و فریمورک هایی مثل ری اکت و انگولار ازش استفاده میشه البته اگه پروژه بزرگ و پیچیده باشه مناسبتره در غیر اینصورت چیزایی مثل context api  کفایت میکنهتوی این مقاله قراره هم مفهومات ریداکس رو یاد بگیریم و هم ساختار و نحوه نوشتنش رو (کسایی هستن که مفهومات رو بلدن ولی نمیدونن چطور ریداکس رو پیاده کنن) پس من روند پیاده سازیشو قدم به قدم پیش میبرم و در حین پیش بردن توضیحات لازم رو هم میدم1. نصب موارد لازمnpm install redux react-redux redux-thunkاز redux برای نوشتن store استفاده میکنیم و از react-redux  برای ارتباط گرفتن ری اکت و ریداکس استفاده میشه برای مثال تغییر دادن دیتای توی store و یا خوندن دیتای مربوطه از استیت گلوبال و از redux-thunk هم برای اضافه کردن قابلیت async به اکشن هایی که باید به صورت async باشن استفاده میشه چون در صورت عادی redux به اکشن ها اجازه نمیده به صورت asynchronous نوشته بشن2.ساخت پوشه redux در پروژه پوشه redux شامل دو پوشه actions , reducers هست:پوشه actions شامل یه فایل index هستش که قراره فانکشنهایی رو برای دستور های مختلف توش بنویسیم برای مثال :اکشن asyncهمونطور که توی عکس بالا میبینید اکشن در واقع یه فانشکن هستش که برای عملکرد خاصی نوشته میشه و در نتیجه دیتایی رو با یه اسم(type) به خصوصی مخابره(dispatch) میکنه به ردیوسر توی عکس بالا فانکشن همونطور که از اسمش پیداس برای گرفتن اطلاعات محصول نوشته شده ولی اگه دقت کنیم داره یه فانکشن async بر میگردونه که مابقی کار رو اون انجام میده ! قضیه چیه؟ما برای استفاده async از اکشن ها نیاز به redux thunk که مارو قادر به نوشتن اکشن async میکنه و نحوه نوشتن اکشن async به شکل بالاس اما یه اکشن ساده به شکل زیره:اکشن sync2. پوشه reducers شامل فایل های ردیوسر مختلف برای اکشن های مختلف با اسم های xxxReducer.js (بجای xxxهرچی میتونید بزارید) هستش و یه فایل index به شکل زیر:ما میتونیم از تک تک فایل های ردیوسر به صورت مستقیم استفاده کنیم و نیازی به ایندکس نداشته باشیم اما برای مرتب تر شدن ما فایل index رو به شکل زیر استفاده میکنیم:ما با استفاده از combineReducer تمام دیتاهایی که ردیوسر ها برمیگردونن رو توی یه آبجکت جمع میکنیم تا استفاده ازشون خیلی ساده تر باشهتوی عکس بالا ما دیتایی که از ردیوسر productsReducer برگشته رو ریختیم توی پراپرتی products هرجا بخوایم با این اسم میتونیم از دیتا استفاده کنیمهر فایل ردیوسر هم به شکل زیر هست :فایل xxxReducer ما شامل یه فانشکن هستش که دوتا پارامتر میگیره اولی state هستش که باید یه مقدار اولیه هم بهش بدید در عکس بالا یه آبجکت خالی هستش و پارامتر دوم action هستش که اگه توی عکسای بالاتر توجه کرده باشید این action در اصل یه آبجکته که از فانکشن اکشن مخابره شده :{type: &#x27;GET_PRODUCTS_DETAILS&#x27; , payload: Product}داخل فانکشن ما از switchاستفاده میکنیم که اسم اکشن مخابره شده رو ( همون type) رو چک بکنیم و در ازای هر اسمی دیتای به خصوص خودشو ( همون payload) رو برگردونیم و در صورت نبودن هیچ کدوم از اسما همون استیت پیشفرض رو برمیگردونیم و این دیتا توی پراپرتی مخصوص خودش توی آبجکت RootReducerذخیره میکنیم:حالا این دیتا هر جایی با اسم ProductDetailsدر دسترس هستش3. ایجاد store و provider در فایل root پروژهما برای دسترسی به دیتایی که توسط اکشن ها و ردیوسر ها دست به دست میشن و توی rootReducer قرار میگیرن نیاز داریم تا توی فایل روت کارایی رو انجام میدیمخب ما مثل عکس بالا توی فایل index باید store رو به وسیله createStore بسازیم که پارامتر اولش rootReducer هست که با combineReducer ساخته شده تا به همه دیتاهایی که ردیوسر ها برمیگردونن یه جا توی یه ابجکت دسترسی داشته باشیم و پارامتر دوم applyMiddleWare هستش که میاد thunk رو به عنوان یه واسط به ریداکس اضافه میکنه تا بتونیم اکشن های async هم انجام بدیم و در آخر با provider دور کامپوننت App که هفت جد و آباد همه ی کامپوننتای دیگس محاصره میکنیم و بهش پراپی میدیم که استور رو دربر داره و حالا هر کامپوننتی داخل app.js هر چقدر هم تو در تو باشه میتونه به صورت مستقیم به هر دیتایی دسترسی داشته باشه بدون اینکه از بالا تا پایین یکی یکی فلان دیتا رو بهش پاس بدیم که در ادامه میگم چطور.4. استفاده از اکشن ها و استفاده از ردیوسر هاخب لپ کلام بخوام بگم اینطوریه که ما یا میخوایم یه اکشن رو بفرستیم تا دیتا رو تغییر بده و یا میخوایم دیتایی که تغییر کرده رو از ردیوسر بگیریم و توی یو ای نمایش بدیمارسال یا مخابره یک دستور(اکشن):همونطور که تو عکس بالا میبینید ما برای استفاده از هر اکشنی اول اون اکشن رو از redux/actions ایمپورت میکنیم و بعد با استفاده از useDispatch اکشنمون رو مخابره میکنیم.2. گرفتن دیتا از ردیوسر:خب اگه یادتون باشه بالا تر توی rootReducer ما دیتایی که از یکی از ردیوسر ها برگشته بود رو روی پراپرتی productDetails ریختیم و توی عکس بالا میبینیم که میتونیم با استفاده از useSelector یه کال بک انجام بدیم که یه پارامتر میگیره که همون rootReducer هستش (تو عکس بالا با اسم state) و از این استیت دقیقا دیتایی که میخوایم رو میگیریم و میریزیم توی متغیر و تو ui نمایشش میدیم به همین سادگی!توی گیف پایین تموم روند که بالاتر گفتم رو یجا میبینید:فرستادن اکشن از ui به reducer و اپدیت کردن state توسط ردیوسر در داخل استیت و در نهایت آپدیت شدن uiخب اگه تا اینجا خوندی و خسته نشدی بیا تا یه اموزش کوچیک هم در ادامه بهت بدم اونم استفاده از redux persist هستش که برای استفاده ازش فقط کافیه یه کوچولو فایل src/index.js رو تغییر بدیم اما اصلا redux persist چی هستش؟مطمعنا خیلیاتون دلتون میخواد دیتایی که هر سری اپدیت میکنید رو نگه دارید و طوری نباشه که با یه رفرش همش بپره!خب این پکیج دقیقا برای همینه که میاد هر دیتارو که از ردیوسر میگیره و توی لوکال استوریج ذخیره میکنه تا با رفرش کردن اون دیتا نپرن!برای استفاده ازش اول اینطوری نصبش کنید:npm install redux-persistبعدش فایل روت رو بجای اون تغییراتی که بالاتر گفتم اینطوری بزارید :چیزایی که لازمه رو طبق عکس بالا از Redux persist ایمپورت میکنیم.آبجکت persistConfig میاد تنظیم میکنه که دقیقا چیو چجوری سیو کنه تو لوکال مثلا ردیوسری داریم که نمیخوایم توی لوکال ذخیره بشه دیتاش و با هر رفرش ناپدید شه از پراپرتی blackList که آرایه هست استفاده میکنیم و اسمی که توی RootReducer به این ردیوسر دادیم رو به صورت استرینج توی این آرایه قرار میدیم.متغیر persistedReducer میاد قبل از استور rootReducer رو میگیره و ذخیره میکنه و حالا به Store به عنوان پارامتر اول بجای rootReducer میایم متغیر persistedReducer رو پاس میدیم که با هر رفرش خالی نکنه دیتا رو ما باید App رو علاوه بر provider با PersistGate هم بپوشونیم که که متغیر persistor هم حکم Store برای PersistGate رو داره و loading هم پراپی هستش که میدیم تا لود شدن دیتا بیاد و اونو نمایش بده مثلا : laoding={&lt;Loading /&gt;} .فقط حواستون باشه چه مقدار دیتا و چه دیتایی توی لوکال ذخیره میکنید چون هم فضاش محدوده و هم میتونه دیتایی باشه که نخواید توی لوکال استوریج ذخیره شهخب این مقاله اینجا تموم شد و دیدیم که ریداکس همچین غول زشت و بی شاخ و دمی هم که ازش میترسن نیست و برعکس خیلی هم عالیه :)امیدوارم خسته نشده باشی و بدردت خورده باشهخدانگهدار موفق باشی?</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Mon, 20 Dec 2021 16:48:13 +0330</pubDate>
            </item>
                    <item>
                <title>استفاده از هوک ها در ری اکت</title>
                <link>https://virgool.io/@samAghapour/hooks-in-react-sam-aghapour-wroonuzrnjxn</link>
                <description>تو پست قبلی درمورد متد های lifeCycle  در کلاس کامپوننت ها صحبت کردیم و کارایی تک تکشون رو گفتیم که قبل از ورژن 16.8 ری اکت ما برای نوشتن کامپوننت های stateful و فیچر های دیگه ازشون در کلاس کامپوننت ها استفاده میکردیم؛ اما بعد از ورژن 16.8 ، هوک ها اومدن و همه چیزو تغییر دادن ، طوری که دیگه لازم نبود برای نوشتن کامپوننت های stateful از کلاس کامپوننت استفاده کنیم و فانکشنال کامپوننت با استفاده از هوک ها تقریبا همه ی چیزایی که با کلاس کامپوننت ممکن بود رو بهمون داد، ما امروز میخوایم درمورد یه سری از این هوک ها صحبت کنیم که خودِ ری اکت برامون به جا گذاشته و تقریبا همیشه از اکثر این هوک ها استفاده میشه.1.UseEffectساید افکت چیست؟ !وقتی یه فانکشن مینویسیم که اجزای داخلش به یه چیزی در بیرونِ اسکوپ خودش تاثیر میزاره میگن ساید افکت. برای مثال: data fetching ، دستکاری دام ، ست کردن و گرفتن لوکال استوریج ، setInterval و setTimeout و...با استفاده از هوک useEffect ما هر ساید افکتی که داریم رو میتونیم داخل این هوک اجرا کنیم اگه توی پست قبلی یادتون باشه ما اینکارو با componentDidMount و componentDidUpdate انجام میدادیم، خب این هوک جفت متد رو باهم تو خودش داره و فرق با این دو متد لایف سایکل اینه که:متد های لایف سایکل بعد از اجرا شدن رندر و قبل از پینت شدن محتوا اجرا میشن و اگه ui رو داخل این متد ها دستکاری کنیم ،متوجهِ تفاوتی که بین ui اپدیت شدمون و ui قبلی اتفاق افتاد نمیشیم چون قبل پینت شدن روی صفحه دستکاری رو اعمال کردیم اما هوک useEffect دقیقا بعد از پینت شدن ui میاد اجرا میشه و اگه مثلا بک گراند یه المنت رو از داخل این هوک از سفید به قرمز تغییر بدیم، حتی واسه یه لحظه هم که شده اول بک گراند قبلی که سفیده رو میبینیم و بعد بک گراند به رنگ قرمز در میاد که اینجا یه امتیاز مثبت واسه متد لایف سایکل به حساب میاد که البته با هوک useLayoutEffect میتونیم میتونیم همون ویژگی لایف سایکل رو با این هوک به وجود بیاریم که جلوتر درموردش حرف خواهم زد.پینت شدن چیست؟بعد از اجرا شدن رندر ،مرورگر محتوایی که ریترن شده رو روی صفحه به نمایش در میاره که اصطلاحا بهش painting میگن.زمان اجرای useEffectبه طور کلی میتونیم به useEffect به این شکل نگاه کنیم که یه هوکه که خودش سه تا متد componentDidMount و componentDidUpdateو componentWillUnmount رو اجرا میکنه ، اما به چه شکلجایگزین کردن useEffect با متد های لایف سایکلتوی عکس بالا useEffect به سه شکل برای سه متد اجرا شده تا دقیقا همون کارایی متد لایف سایکل رو داشته باشه که اینجا به ترتیب توصیح میدمشuseEffect(() =&gt; { 
//side Effecst
},[ ])به طور کل useEffect دو تا آرگیومنت میگیره که اولی یه کال بک هستش که ساید افکت هامون رو توش مینویسیم و آرگیومنت دوم یه آرایه اختیاری هستش که میتونیم بزاریم یا نزاریم و با خالی گذاشتنش مثل کد بالا به ری اکت میگیم که این کال بک رو فقط یک بار دفعه ی اول اجراش کن مثل componentDidMount.useEffect(() =&gt; { 
//side effects
 })یاuseEffect(() =&gt; {
//side effects
},[dependency])اگه آرگیومنت دوم رو نزاریم useEffect بعد هر بار رندر اجرا میشه و اگه آرگیومنت دوم رو بزاریم و داخلش یه دپدنسی بدیم فقط وقتایی که اون دپدنسی مقدارش تغییر کنه اینم اجرا میشه مثلا یه استیت به عنوان دپندنسی به آرایه میدیم هر بار که اون استیت تغییر کنه این کال بک اجرا میشه (دفعه ی اول هم این شکل از useEffect اجرا میشه) دقیقا مثل componentDidUpdate.clean up in useEffectتوی کد بالا ما یک ساید افکت رو داخل کال بک انجام میدیم اما بعدش یه فانکشن هم ریترن میکنیم که به این فانکشنی که توسط کال بک ریترن میشه میگیم clean up و داخل این فانکشن همه ی ساید افکتامون رو کنسل میکنین و یجورایی تمیز میکنیم کال بکمون رو و این فانکشن در دو زمان اجرا میشه ،اول وقتی که کامپوننت حذف میشه مثل componentWillUnmount و دوم وقتی که کامپوننت ری رندر میشه اول میاد این فانکشن رو اجرا میکنه تا ساید افکتای قبلی رو حذف کنه و حالا بعدش ساید افکتای رندر جدید رو اجرا کنهپس به طور خلاصه فانکشن clean up قبل از ساید افکتای داخل کال بک اجرا میشه تا مسیر رو برای اجرای ساید افکتای جدید تمیز کرده باشه.هوک useEffect نکات ریز و درشت زیادی داره که در این مقاله نمیگنجه اگه خواستید بیشتر درموردش بدونید میتونید به داکیومنت خود ری اکت مراجعه کنید.2.useLayoutEffectتوی هوک قبلی گفتیم که useEffect توی دستکاری دام یکم ضعف داره چون بعد از پینت شدن ui اجرا میشه ، حالا این هوک اومده که اون ضعف رو بپوشونه.این هوک دقیقا بعد از اجرای رندر و قبل از پینت شدن  ui اجرا میشه زمان اجرای useLayoutEffectما توی اکثر مواقع از useEffect استفاده میکنیم اما توی این یه مورد ( دستکاری دام) از این هوک استفاده میکنیممرورگر ui رو روی صفحه پینت نمیکنه تا این هوک کارش تموم شه پس حواستون باشه که چجوری ازش استفاده میکنید که مشکل پرفورمنس براتون به وجود نیاره همونطور که گفتم اکثر مواقع و برای اکثر کارها همون useEffect کارمون رو راه میندازه.3.useStateقبل از اینکه هوک ها ظهور کنن ما از state ها نمیتونستیم توی فانکشنال کامپوننت استفاده کنیم و باید از this.state در کلاس کامپوننت ها استفاده میکردیم، اما الان با این هوک دیگه نیازی به کلاس کامپوننت ها نیست.const MyState =useState(&#039;default value&#039;)مقداری که MyState بهمون میده یه آرایه هستش که شامل دوتا آیتم هستش، آیتم اول مقدار پیشفرض استیت که به عنوان آرگیومنت به هوک useState دادیم هست  و آیتم دوم یه فانکشن برای آپدیت این مقدار هستش که باعث میشه اکثر برنامه نویسا موقع استفاده از این هوک ، از Array destructuring استفاده کنن.نوشتن هوک به شکل array destructuringاولین مقدار داخل آرایه  (state) : اسم استیتِ ماست.دومین مقدار داخل آرایه ( setState) : اسم فانکشنی که باهاش استیت رو آپدیت میکنیم هستش میتونیم بجای state و setState هر اسم دیگه ای به این دو بدیم مثل count و setCount و..آرگیومنتی که به هوک useState دادیم مقدار پیشفرض این استیت هستش که توی عکس بالا یه آبجکته.یکی از نکاتی که باید بهش توجه کنید اینه که بر موقع استفاده از setState اگه مثلا بخوایم مقدار داخل آبجکت این استیت رو بروزرسانی کنیم و یه پراپرتی جدید به قبلیا اضافه کنیم react متوجه نمیشه که ما قصدمون فقط بروزرسانی هستش نه جایگزینی کل آبجکت،پس میاد کل ابجکت رو تغییر میده.توی کد بالا وقتی از setUser استفاده میکنیم نمیاد فقط آبجکت user3 رو به دوتا ی قبلی که به صورت دیفالت تو استیت هستن اضافه و اپدیتش کنه، بلکه میاد کل استیت رو به فقط آبجکت user3 تغییر میده!واسه جلوگیری از این اتفاق باید اینو بدونید که فانکشن setState یه آرگیومنت میگیره که مقدارش همون مقادیر قبلی داخل استیت هستش و از اون برای بروزرسانی استیت استفاده میکنیم حالا اگه ابجکت یا آرایه باشه با spread operator (...) یا اگه یه استرینج یا عدد خالی باشه بدون spread operator  به شکل زیر انجامش میدیم4.useRefاز این هوک اغلب برای دوتا کار استفاده میشه:دسترسی مستقیم به المنت های DOMنگه داشتن یک مقدار برای کارایی شماره یک شاید این سوال براتون به وجود بیاد که فرقش با DOM selectors مثل queryselector چیه؟خب وقتی از DOM selector ها استفاده میکنیم برای پیدا کردن المنت باید کل ساختار درختی DOM رو بگرده تا پیداش کنه درحالی که با استفاده از useRef ما مستقیما آدرس اون المنت رو بهش دادیم و نیازی به پیمایش نداره و این خودش هرچند خیلی کم ولی بازم یه کوچولو تو بهتر کردن پرفورمنس تاثیر مثبت داره و فرق دیگش هم اینه که useRef از چرخه ی زندگی یه کامپوننت باخبره و react میدونه که کی باید مقدارش رو null بده و کی المنت رو بهش پاس بده و در کل وقتی داریم از یه فریمورک یا لایبرری استفاده میکنیم بهتره که از چیزایی که خود اونا میشنهاد میدن استفاده کنیم که حتما یه منفعتی داره.حالا چجوری نوشته میشه؟آدرس دهی از المنت به useRefوقتی از useRefاستفاده میکنیم به ما یه ابجکت برمیگردونه که شامل یه پراپرتی به اسم current هستش که داخل اون المنتی که بهش رفرنس دادیم رو نگه میداره البته در ابتدا وقتی که هنوز رفرنسی ندادیم بهش ،مقدار پیشفرضی که به عنوان ارگیومنت به هوک دادیم رو تو current نگه میداره که حالا میتونه null باشه.برای کارایی شماره دو هم شاید این سوال میش بیاد که تا وقتی state هست چرا باید بخوام یه مقداری رو توی current این هوک نگه دارم که خب فرقش با state اینه که مقداری که به این هوک میدیم تا نگه داره اگه تغییر کنه باعث ری رندر شدن کامپوننت نمیشه درحالی که تغییر مقدتر استیت باعث ری رندر شدن میشهپس وقتی که مقداری داریم که بدون توجه به لایف سایکلِ کامپوننت ، همیشه در دسترسه و نیازی نیست که تغییرش باعث ری رندر بشه بهتره که توی useRef نگه داریش کنیم.پس ()createRef چیست؟این هم فرقش با useRef اینه که با هر بار ری رندر شدن مقدار داخلش دوباره از نو ایجاد میشه اما useRef اینطور نیست و بین ری رندرینگ هم مقدار داخلش رو نگه میدارهاینا از مهمترین هوک هایی بودن که باید بلد میشدین و از زیر سایه کلاس کامپوننت ها خارج میشدین. دو هوک مهم دیگه useContext و useReducer هستن که بهم مرتبطن و جدا جدا توضیح دادنشون فکر خوبی نیست و همینطور به مبحث state managment مربوط میشن و توی یه پست جدا درموردشون صحبت خواهم کرد.خسته نباشی ، این مقاله اینجا به پایان میرسه. خدانگهدار موفق باشی?</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Thu, 07 Oct 2021 17:18:46 +0330</pubDate>
            </item>
                    <item>
                <title>یکبار برای همیشه React Lifecycle رو یاد بگیر</title>
                <link>https://virgool.io/@samAghapour/sam-react-lifecycle-lwpyqkz6ped7</link>
                <description>4 مرحله از زندگی یک کامپوننت ری اکتخب خب قبل شروع بزار بگم که با خوندن این مقاله قراره چی نصیبت بشهتوی این مقاله کل lifecycle یا چرخه زندگی رو قراره زیر و رو کنیم و با مثالای خیلی تمیز سعی میکنیم زمان وقوع هر متد و نحوه نوشتن و سینتکس متد های lifecycle رو و به بیان دیگه قراره کل جد و آباد متد های چرخه ی زندگی رو بیاریم وسط! بریم که رفتیماصلا lifeCycle ینی چی؟اگه بخوام خودتو مثال بزنم ، تو توی طول زندگیت یه چرخه ای رو دنبال میکنی که مطمعنن میتونی حدس بزنی این چرخه همون چرخه ی زندگی هستش ، قبل اینکه به دنیا بیای احتمالا برات اسم و دین و.. انتخاب کردن و اسم پدر و مادرت و... مشخصه (initialization) ، توی مرحله بعدی تو به دنیا میای ( mounting ) ، مرحله بعدی   مرحله ی بزرگ شدن و تغییر کردنت هستش ( updating ) و مرحله ی آخر مثل هر چرخه ی زندگی ای به مرگ و پایان ختم میشه ( unmounting ).این یه مثال ساده و مختصر از چرخه ی زندگی بود که توی همه چی به همین شکل جریان داره و کامپوننت های ری اکت هم از این قضیه مستثنی نیستند. حالا قراره در عین حال که این مراحل و متد هاشو در ادامه توضیح میدم برای مثال هاشون از همین مثال بالا استفاده کنم.توی ری اکت مراحل lifecycle به چه ترتیب زمانی هستند؟1. مرحله اول : initialization یا مقداردهی اولیه هستش...توی این مرحله استیت ها و هرچی که نیازشه رو مقداردهی اولیه میکنیمinitialization2.مرحله دوم : mounting یا به وجود اومدن هستش...توی این مرحله متد render  اجرا میشه و کامپوننت به وجود میاد3. مرحله ی سوم : updating یا بروزرسانی و تغییر هستش...توی این مرحله کامپوننت با پراپ ها و استیت هاش رابطه مستقیم داره که باعث تغییرش میشن.چطور؟   اگه یه سنگ به سمت صورتت پرت کنن چی میشه؟ چون اون تیکه از صورتت که قبلا زخم نبود زخم میشه درسته؟ پس یه تغییری کردی به این میگن اپدیت شدن.حالا اگه همون سنگ به همون شکل و با همون سرعت پرت شه و به همون نقطه از صورتت بخوره تو تغییری نمیکنی چون اون زخم از قبل اونجا هست و اون نوع سنگ و نحوه و سرعت پرتابش و محل برخوردش هیچ تغییری نکرده که باعث تغییر خاصی در تو بشه اما اگه دفعه ی بعد اون سنگه بزرگتر باشه جای زخمشم بزرگتر خواهد بود و تو باز تغییر خواهی کرد ( مطمعنم مثالای بهتری الان توی سرت هست و من با زدن همچین مثالایی فقط سعی میکنم طوری بگم که این مرحله از چرخه رو درست درک کنی. فقط امیدوارم با این مثالا تا اخر این مقاله به کشتن نداده باشمت =)))) )پس نتیجه گرفتیم که این سنگه همون پراپ هستش و تو همون کامپوننت هستی اگه پراپی که به سمت کامپوننت میندازن تغییر کنه همین باعث تغییر کامپوننت هم میشه و در غیر اینصورت چیزی نباید تغییر بکنه. جلوتر بیشتر از جزییاتش حرف میزنم فلن تا اینجا واسه این بسه.4. مرحله ی آخر: unmounting یا حذف شدن نابود شدن مرگ یا حالا هرچی که اسمشو میزاری.توی این مرحله با یه کلیک به صفحه ی دیگه یا حالا با یه رویداد خاصی دیگه به این کامپوننت نیازی نیست و باید حذف بشه دیگه مثالشو تو زندگی خودمون میتونی حدس بزنی.متد های هر یک از مراحل چرخه ی زندگی کدام ها هستند و چگونه کار میکنند؟1. مرحله ی initialization که چیزی نداره و فقط شامل همون constructor و super و setState هستش.2. مرحله ی mounting :componentWillMount(){
  //code
}این متد فقط بار اول و قبل از متد render اجرا میشه ینی قبل از به وجود اومدن کامپوننت و داخلش میتونی تصمیم بگیری که قبل از به وجود اومدن کامپوننت چه اتفاقی بیفتهتوجه: این متد از سال 2018 به بعد منقضی شد و فقط تا ورژن 17 ری اکت میشه ازش استفاده کرد و بعد از اون بهتره که یا از روش های جایگزین استفاده کنی به اسمش کلمه ی _UNSAFE رو اضافه کنیدلیل انقضا : ری اکت دید که وقتی توی این متد عملیات Asynchronous مثل data fetching انجام میدیم باعث ری رندر شدن بیش از یکبار کامپوننت و ایجاد تداخل میشه ، چرا؟ چون این متد باید قبل از متد رندر اجرا بشه ولی کد غیر همزمان داخلش هم باید بعد از متد رندر اجرا بشه چون همونطور که تو مقاله قبلی توضیح دادم متد رندر که synchronous هستش اجرا شدنش مقدم هست بر توابع asynchronous و همین باعث تداخل میشهجایگزین هاش چی هستن؟ برای عملیات asynchronous بهتره از componentDidMount استفاده کرد و برای عملیات غیر همزمان میتونی از همین متد UNSAFE_componentWillMount استفاده کنی که البته پیشنهاد نمیشه یا ام که تو همون Constructor  کارتو راه بندازی.componentDidMount(){
  // code
}این متد فقط بار اول و بعد از متد render اجرا میشه (وقتی میگم بعد از متد render منظورم اینه که بعد از اینکه کامپوننت به وجود میاد و میره رو صفحه). توی این متد میتونی یه بلایی سر کامپوننت بعد از اینکه به وجود میاد و میره روی صفحه بیاری ، میتونی عملیات asynchronous انجام بدی.3. مرحله updating: shouldComponentUpdate(newProps,newState){
   //اگه پراپی که گرفتیم با اینی که از قبل داریم فرق داشته باشه این متد به ما ترو میده در غیر اینصورت فالس میده    newProps.value !== this.props.value    }این متد دفعه ی اول اجرا نمیشه و از دفعات بعد، قبل هر ری رندر اجرا میشه .یادتونه بالاتر مثال پرتاب سنگ به صورت رو برای اپدیت شدن زدم؟ خب یه جای کار با مثالی که زدم فرق داره اونم اینه که توی ری اکت حتی اگه پراپ تغییری نکرده باشه بازم باعث میشه جهت محکم کاری اپدیت (re-render ) بشه اونم بخاطر اینه که این متد ( shouldComponentUpdate ) به طور پیش فرض true برمیگردونه و همین true ، باعث re-render شدن میشه . در کل از این متد برای جلوگیری از این اتفاق ( re-render شدن الکی) استفاده میشه که فقط وقتی پراپ متفاوت بود ری رندر بشه که در نتیجه باعث بالا رفتن سرعت سایتمون میشه. فقط کافیه ( nextProps.value !== this.props.value ) رو بزارید داخل متد تا دیگه سر خود هر سری true برنگردونه.توجه: اگه این متد false برگردونه مانع اجرا شدن متد های render و componentWillUpdate و componentDidUpdate میشه.componentWillUpdate(newProps,newState){  // code اگه متد بالایی ترو برگردونه باشه این متد اجرا میشه}این متد هم دفعه ی اول اجرا نمیشه و از دفعات بعد،  قبل هر ری رندر اجرا میشه  و توش میشه قبل از اپدیت شدن کامپوننت یه بلایی سرش آورد و دستکاریش کرد.توجه: این متد از ورژن 16.6 به بعد ری اکت منقضی شد و فقط تا ورژن 17 ری اکت میشه ازش استفاده کرد و بعد از اون بهتره که یا از روش های جایگزین استفاده کنی به اسمش کلمه ی _UNSAFE رو اضافه کنی.دلیل انقضا: از ورژن 16.6 به بعد ری اکت یه قابلیتی آورد به اسم suspense , lazy react component که کارشون اینه که متد render رو از synchronous به asynchronous تبدیل و رندر شدن یه کامپوننت رو به تاخیر بندازن که باعث پرفورمنس بهتر میشه اما این قابلیت زد خااره این متد ( componentWillUpdate ) رو تار کرد ، چطور؟!   غیرهمزمان شدن متد render باعث تداخل بین این متد و componentWillUpdate  میشه چون تو هر بلایی که سر dom بخوای بیاری یا یه مقداریشو بگیری باید صبر کنه تا Dom بالا اول بیاد.جایگزین هاش چی هستند؟یا از همین متد UNSAFE_componentWillUpdate باید استفاده کرد که اصلا پیشنهاد نمیشه یا از یه متد جدید بعد از این معرفیش میکنم.getSnapshotBeforeUpdate(prevProps,PrevState){   //code}این متد قبل از re-render و اپدیت شدن اتفاق میفته و میاد یه سری اطلاعات رو از همین کامپوننتی که هنوز اپدیت نشده میچینه و نگهش میداره که شاید بدردمون بخوره...این اطلاعاتی که چیده رو ریترن میکنه اما خب مقدارش رو کجا میتونیم استفاده بکنیم؟ مقداری که ریترن میکنه به عنوان ارگومان سوم پاس داده میشه به متد componentDidUpdate که بعد از این معرفیش میکنم. همونطور که بالاتر گفتم این یه متد هستش که جایگزین componentWillUpdate شده و شاید سوال براتون پیش بیاد که این با رندر asynchronous  مشکلی نداره؟ خب باید بگم نه چون این قرار نیست از کامپوننتی که هنوز لود نشده اطلاعات بگیره که بخاطرش هم بخواد واسته ، این قراره از کامپوننت ورژن قبلی این اطلاعات رو بگیره که همه چی توش موجوده و هنوز اپدیت نشده.شاید وقتی اولین بار اینو میخونی فک کنی این دوتا کاراییشون فرق دارن و احمقانس این رو جایگزین برای اون دونسته باشن اما وقتی باهاش کار کنید میبینید هرکاری با منقضیا میکردید با همین جایگزیناشونم میتونید بکنید( این جایگزین هارو خود ری اکت پیشنهاد کرده ).فقط دوتا متد موند رفیق، بیا تمومش کنیم.componentDidUpdate(prevProps,prevState,Snapshot){if( prevProps.value !== this.props.value){// code یادتون نره کداتون رو داخل این شرط اجرا کنید تا به خطای حلقه ی بینهایت نخورید}}این متد بار اول اجرا نمیشه و فقط بعد از re-render و اپدیت شدن اجرا میشه و همونطور که میبینید مقداری که توی متد بالا (getSnapshotBeforeUpdate ) ریترن شده اینجا میتونیم ازش استفاده کنیم (Snapshot)4. مرحله Unmounting : componentWillUnmount(){//clean up}خب این تنها متد برای این مرحله هستش.وقتی یه کامپوننت داره حذف میشه این متد اجرا میشه و در حقیقت کارش اینه که هر چی network request و تایمر و در کل هر چی که در طول حیات این کامپوننت داره اجرا میشه رو کنسل میکنه تا در نبود این کامپوننت این request ها هم الکی اجرا نشن و سرعت سایت بره بالاتر.بلخره تموم شد،  اینم فلوچارت این متد ها که بتونی ترتیب اجرا شدنشون رو درک کنی و بهتر استفادشون کنی:react lifecycle flowchart این متد ها و نحوه و زمان کارکردشون از مباحث مهمی بود که باید یاد میگرفتی هرچند که الان با وجود فانکشنال کامپوننت و هوک ها و... که در مقاله های آینده راجبشون حرف خواهم زد، کمتر مزاحم این عزیزان میشیم.خسته نباشی و ممنون که تا آخر با حوصله این مقاله رو خوندی.خدانگهدار?</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Sat, 11 Sep 2021 23:40:35 +0430</pubDate>
            </item>
                    <item>
                <title>پشت پرده ی جاوا اسکریپت! توابع asynchronous چطور کار میکنند؟</title>
                <link>https://virgool.io/@samAghapour/samaghapour-eventloop-ifujq6fj4fsp</link>
                <description>توی این مقاله بهت توضیح میدم چطور جاوااسکریپت در پشت پرده توابع asynchronous , synchronous  رو هندل میکنهjavaScript Event loops , call stack , callback queueسعی میکنم مقاله رو تا حد امکان مختصر و مفید بنویسم که خسته نشید خیله خب بریم سر اصل مطلب..مفهوم Call Stack در جاوااسکریپتوقتی توی جاوااسریپت یه سری تابع تعریف میکنیم و صداشون میکنیم این توابع به جدولی به اسم call stack فرستاده میشن تا اجرا بشن و بعد از اجرا شدن از اون جدول خارج میشن.توی این گیف میتونید ببینید که توابع به ترتیبی که صدا زده میشن میرن داخل call stack و بعد از اجرا شدن خارج میشن.خب تا اینجای کار آسون بود اما یه چیزی که تو گیف بالا توجه رو جلب میکنه وجود تابع asynchronous داخل تابع respond  هستش که قرار نیست کارش به همین جدول Call stack ختم بشه که جلوتر بیشتر توضیح میدم اما قبل از ورود به اون مرحله بیاید گیف بالا رو  بشکافیم تا بهتر درکش کنیم. تابع greet  صدا زده میشهاین تابع میره تو call stack تا اجرا بشه حالا call stack ، این تابع رو اجرا میکنه و مقدار hello رو برمیگردونه و از صف خارجش میکنه تا بعدی بیاد جلوتابع respond وارد call stack میشه که دقیقا پشت سر greet  صدا زده شده بود و همین مراحل بالا رو تا مرحله 3 طی میکنه. مفهوم Web APIs ( Events table ) و Callback Queue و  Event Loop در جاوااسکریپت معرفی Web APIs یا Events Table : ما هر فانکشن asynchronous ای داشته باشیم مثل setTimeout و Ajax  و  EventHandler ها به این جدول اضافه میشن، اینطوری فکر کنید که هر تابعی که باید بعد از یه مدت مشخص یا بعد از یه event  خاصی مثل کلیک یا اسکرول و... انجام بشن میرن تو جدول event table یا همون web APIs و تا زمانی که زمان اجراشون برسه توی همین جدول میمونن، مثلا تا وقتی که فلان کلیک زده بشه(event handler )  یا فلان زمان تموم بشه ( timeout)، اما خب بعد از این کجا میرن؟! معرفی Callback Queue : همونطور که از اسمش پیداس این یه صف برای callback ها هستش و بس ! وقتی یه callback که قرار بود بعد از سه ثانیه اجرا شه زمانش فرا میرسه یا یه callback که قرار بود بعد از کلیک اجرا شه کلیکش زده میشه ، از event table خارج و به ترتیب به این صف اضافه میشه، این صف نه این هارو اجرا میکنه و نه میفرستتشون به call stack  خب پس چیکارس؟معرفی Event Loop : این داداشمون یه واسطه بین callback queue و call stack هستش، Event loop یکسره حواسش به این دوتا هست و وظیفش انتقال callback های داخل صف callback queue  به call stack هستش تا اجرا شن اما تا call stack خالی نشه ایشون callback  هارو برای اجرا شدن نمیفرسته، به محض اینکه استک خالی شه ایشون میاد و اولین کال بک رو میفرسته تا اجرا شه و طبق معمول کال بک بعد از اجرا شدن مثل بقیه فانکشن ها از استک خارج میشه خب تا اینجا با همشون آشنا شدیم حالا بیاید توی یه گیف کاربردی ببینیم چطور این عزیزان باهم کار میکنن.اول یه دور به تابع bar و کال بکِ اون نگاه کنید و یه دور به دوتا تابع بعدیش نگاه کنیدشاید بهتر باشه اتفاقای توی گیف رو به صورت کد هم ببینید: با اینکه bar اول صدا زده شده اما اخر اجرا شد.حالا میتونید ببینید با اینکه bar  اول از همه صدا زده شده اما چون asymchronous  هستش رفته توی یه صف جدا تا زمانش برسه و مابقی توابع قبل از اون صدا زده شدن ، توجه داشته باشید که حتی اگه زمان اجرای setTimeout  رو روی صفر ثانیه هم بزارید بازم میمونه آخر اجرا میشه، چون در هر صورت این تابع asymchronous هستش که باعث خروجش از Call stack  میشه.خب خسته نباشی، این مقاله اینجا تموم میشه و خوشحالم که تونستی دانش برنامه نویسیت رو بیشتر توسعه بدی. تا مقاله های بعدی خدانگهدار ?</description>
                <category>Sam Aghapour</category>
                <author>Sam Aghapour</author>
                <pubDate>Tue, 07 Sep 2021 14:23:53 +0430</pubDate>
            </item>
            </channel>
</rss>