<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های فرشید کریمی</title>
        <link>https://virgool.io/feed/@m_21642669</link>
        <description>فرشید کریمی‌ام. یه زمانی مهندسی برق خوندم، کلی توی دنیای embedded دور زدم و با سخت‌افزارها ور رفتم. چند سالیه توسعه وب رو شروع کردم و خیلی به عمیق شدن و فهم مفاهیم پیچیده علاقه‌مندم.</description>
        <language>fa</language>
        <pubDate>2026-06-16 20:45:55</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/1526270/avatar/nwdTMF.jpeg?height=120&amp;width=120</url>
            <title>فرشید کریمی</title>
            <link>https://virgool.io/@m_21642669</link>
        </image>

                    <item>
                <title>تست‌نویسی در javascript/typescript — بخش ۳: تکنیک‌های پیشرفته تست واحد</title>
                <link>https://virgool.io/@m_21642669/%D8%AA%D8%B3%D8%AA-%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D8%AF%D8%B1-javascripttypescript-%E2%80%94-%D8%A8%D8%AE%D8%B4-%DB%B3-%D8%AA%DA%A9%D9%86%DB%8C%DA%A9-%D9%87%D8%A7%DB%8C-%D9%BE%DB%8C%D8%B4%D8%B1%D9%81%D8%AA%D9%87-%D8%AA%D8%B3%D8%AA-%D9%88%D8%A7%D8%AD%D8%AF-rltdpteycotq</link>
                <description>در مقاله قبلی، با مبانی تست واحد و TDD آشنا شدیم. در این مقاله تکنیک‌های پیشرفته تست نویسی واحد رو با هم بررسی می‌کنیم. در این مقاله، ابزارهای قدرتمندی رو یاد می‌گیریم که به ما کمک می‌کنن تست‌های حرفه‌ای‌تر و انعطاف‌پذیر‌تری بنویسیم.تساوی مرجعی و ساختاری (Referential vs Structural Equality)توی جاوااسکریپت (و قطعا تایپ‌اسکریپت)، تفاوت بین toBe و toEqual بسیار مهمه و انتخاب نادرست، می‌تونه به تست‌های اشتباه و گمراه‌کننده منجر بشه. داستان به این حقیقت برمی‌گرده که دو متغیر از نوع ‌reference در جاوااسکریپت، اگر رفرنس مشترکی نداشته باشند، حتی اگرمقادیر کاملا یکسانی داشته باشند، باز هم با هم مساوی نیستند. مثال:let a = { x:1 };
let b = { x:1 };
console.log(a===b); // false
استفاده از toBe (مقایسه مرجعی)متد toBe برای مقایسه مرجعی استفاده می‌شه و مشابه === یا ()Object.is عمل می‌کنه:test(&#039;strings should be strictly equal&#039;, () =&gt; {
  expect(&#039;string&#039;).toBe(&#039;string&#039;);
});

test(&#039;numbers should be strictly equal&#039;, () =&gt; {
  expect(2).toBe(2);
});

test(&#039;booleans should be strictly equal&#039;, () =&gt; {
  expect(true).toBe(true);
  expect(false).toBe(false);
});

test(&#039;undefined and null should be strictly equal to themselves&#039;, () =&gt; {
  expect(undefined).toBe(undefined);
  expect(null).toBe(null);
});
همه تست‌های فوق پاس میشن، اما وقتی به سراغ اشیا و آرایه‌ها می‌ریم، مشکلاتی پیش میاد:test.fails(&#039;objects should not be strictly equal&#039;, () =&gt; {
  expect({ a: 1 }).toBe({ a: 1 }); // it fails!
});

test.fails(&#039;arrays should not be strictly equal&#039;, () =&gt; {
  expect([1, 2, 3]).toBe([1, 2, 3]); // it fails!
});

test.fails(&#039;functions should not be strictly equal&#039;, () =&gt; {
  expect(() =&gt; {}).toBe(() =&gt; {}); // it fails!
});
پس می‌بینیم که استفاده از toBe در چنین مواردی راهکار درستی نیست و باید سراغ toEqual رفت.استفاده از toEqual (مقایسه ساختاری)متد toEqual برای مقایسه ساختاری استفاده می‌شه و به صورت shallow مقادیر رو بررسی می‌کنه:test(&#039;objects with the same properties are equal&#039;, () =&gt; {
  expect({ a: 1, b: 2 }).toEqual({ a: 1, b: 2 });
});

test(&#039;arrays should be equal&#039;, () =&gt; {
  expect([1, 2, 3]).toEqual([1, 2, 3]);
});

test(&#039;nested objects should be equal&#039;, () =&gt; {
  expect({ a: 1, b: { c: 2 } }).toEqual({ a: 1, b: { c: 2 } });
});

test(&#039;multi-dimensional arrays should be equal&#039;, () =&gt; {
  expect([1, [2, 3]]).toEqual([1, [2, 3]]);
});
حالا تمامی تست های فوق به درستی پاس می شوند.تفاوت toEqual و toStrictEqualمتد toStrictEqual نسخه سفت‌وسخت‌تری از toEqual هست:class Person {
  constructor(name) {
    this.name = name;
  }
}

test(&#039;objects with undefined properties are equal to objects without those properties&#039;, () =&gt; {
  expect({ a: 1 }).toEqual({ a: 1, b: undefined }); // ✅ موفق می‌شه
});

test(&#039;objects with undefined properties are NOT strictly equal to objects without those properties&#039;, () =&gt; {
  expect({ a: 1 }).not.toStrictEqual({ a: 1, b: undefined }); // ✅ موفق می‌شه
});

test(&#039;instances are equal to object literals with the same properties&#039;, () =&gt; {
  expect(new Person(&#039;Alice&#039;)).toEqual({ name: &#039;Alice&#039; }); // ✅ موفق می‌شه
});

test(&#039;instances are NOT strictly equal to object literals with the same properties&#039;, () =&gt; {
  expect(new Person(&#039;Alice&#039;)).not.toStrictEqual({ name: &#039;Alice&#039; }); // ✅ موفق می‌شه
});
دقت کنید که در تست‌های فوق با not عدم تساوی رو بررسی کردیم.کدام روش رو انتخاب کنیم؟متد toBe: وقتی می‌خوایم مطمئن بشیم دو متغیر به یک شیء اشاره می‌کننمتد toEqual: وقتی می‌خوایم مطمئن بشیم دو شیء محتوای یکسانی دارن (معمولاً اینو می‌خوایم)متد toStrictEqual: وقتی می‌خوایم نسبت به toEqual دقیقتر باشیم و undefinedها و انواع شیء رو هم بررسی کنیممثال عملی با کلاس‌هااگر بخواهیم یک مثال از مفهوم تساوی اینبار در ساختار کلاسی بزنیم، بدین صورت میشه.class Calculator {
  constructor() {
    this.result = 0;
    this.history = [];
  }

  add(num) {
    this.result += num;
    this.history.push(`+${num}`);
    return this;
  }

  subtract(num) {
    this.result -= num;
    this.history.push(`-${num}`);
    return this;
  }
}
حالا تستش:test(&#039;calculator should work correctly&#039;, () =&gt; {
  const calc = new Calculator();
  calc.add(5).subtract(2);
  
  expect(calc).not.toBe(new Calculator()); // it fails!
  
  expect(calc).toEqual({
    result: 3,
    history: [&#039;+5&#039;, &#039;-2&#039;]
  }); // it success!
});
همسان‌یابی نامتقارن (Asymmetric Matchers)همسان‌یابی نامتقارن بدون شک یکی از قدرتمندترین ابزارهای تست نویسیه. matcher ها به ما اجازه می‌دن فقط قسمت‌هایی از داده‌ها رو تست کنیم که واقعاً مهم هستن و بقیه رو نادیده بگیریم. این کار باعث می‌شه تست‌هامون انعطاف‌پذیرتر و مقاوم‌تر نسبت به تغییرات غیرضروری بشن.چرا از همسان‌یابی نامتقارن استفاده کنیم؟تصور کنید یه API داریم که اطلاعات کاربر رو برمی‌گردونه:{
  id: &quot;user-123&quot;,
  name: &quot;John Doe&quot;,
  email: &quot;john@example.com&quot;,
  createdAt: &quot;2024-01-15T10:30:00Z&quot;,
  lastLogin: &quot;2024-01-20T15:45:00Z&quot;,
  settings: {
    theme: &quot;dark&quot;,
    notifications: true
  }
}
اگه بخوایم این رو با toEqual تست کنیم، باید همه فیلدها رو دقیق مشخص کنیم. این کار تست رو خیلی سفت می‌کنه و با هر تغییر کوچیک (مثلاً تغییر timestamp)، تست fail میشه.همسان‌یابی نامتقارن به ما اجازه می‌دن فقط روی چیزایی تمرکز کنیم که واقعاً برامون مهم هستن.مشاهده مقاله کامل در این آدرس:https://farshidev.ir/Post/%D8%AA%D8%B3%D8%AA%E2%80%8C%D9%86%D9%88%DB%8C%D8%B3%DB%8C-javascript-typescript-unit-test-advancedموفق باشید.</description>
                <category>فرشید کریمی</category>
                <author>فرشید کریمی</author>
                <pubDate>Thu, 19 Feb 2026 06:36:57 +0330</pubDate>
            </item>
                    <item>
                <title>تست‌نویسی در javascript/typescript — بخش ۲: تست واحد یا unit test</title>
                <link>https://virgool.io/@m_21642669/%D8%AA%D8%B3%D8%AA-%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D8%AF%D8%B1-javascripttypescript-%E2%80%94-%D8%A8%D8%AE%D8%B4-%DB%B2-%D8%AA%D8%B3%D8%AA-%D9%88%D8%A7%D8%AD%D8%AF-%DB%8C%D8%A7-unit-test-uwrlu39dazqz</link>
                <description>در این مقاله، قصد داریم وارد دنیای تست واحد (Unit Testing) بشیم. تست واحد یکی از پایهایترین و مهمترین انواع تستهای نرمافزاریه که در اون فقط یک واحد کوچیک از کد (معمولاً یک تابع یا متد) به صورت ایزوله تست میشه.تست واحد به ما کمک میکنه تا:خطاهای اولیه رو سریع شناسایی کنیمتغییرات ایمن داشته باشیم، یعنی وقتی کدمون رو میخواهیم تغییر بدیم، دست و دلمون نلرزه که چندجای دیگه بترکه!اعتماد به نفس بیشتری در ریلیز کردن نسخهها داشته باشیمتوسعه مبتنی بر تست (Test-Driven Development - TDD)قبل از اینکه وارد نوشتن تستها بشیم، واسه اینکه تاکید کنم، تست نوشتن چقدر می تونه مهم باشه باید بگم اصلا ما یک متدولوژی توسعه داریم که برمبنای تست نویسیه و اسمش توسعه مبتنی بر تست یا TDD عه.توی متدولوژی TDD ما اول تست مینویسیم، بعد کد. درباره اینکه چه موقعیه اوکیه این متدولوژی رو استفاده کنیم و چه موقع foul عه بعدا صحبت می کنیم ولی اول بذارید توضیح بدم که چقدر بامزه است، توسعه این سبکی!چرخه Red-Green-Refactorمتدولوژی TDD رو اینجوری پیاده میکنند:قرمز (Red): اول یک تست برای تیکه کدمون مینویسیم که شکست میخورهسبز (Green): حداقل کد ممکن رو مینویسیم تا تست موفق بشهبازنگری (Refactor): کد رو بهبود میدیم بدون اینکه تستها شکست بخورنمثال عملی TDDفرض کنید میخوایم یک تابع برای محاسبه فاکتوریل بنویسیم. دقت کنید ما تابع factorial رو هنوز ننوشتیم و تازه میخواهیم شروع کنیم به نوشتنش. متد TDD به ما میگه اول تستش رو خرد خرد بنویس تا به خودش برسی!مرحله ۱: قرمز (نوشتن تست شکست خورده)اول تست رو مینویسیم: (فعلا بیخیال syntax اش، میگیم جلوتر چیه داستانش!)describe(&#039;factorial&#039;, () =&gt; {
  it(&#039;should calculate factorial of 5&#039;, () =&gt; {
    expect(factorial(5)).toBe(120);
  });
});
این تست حتماً شکست میخوره چون تابع factorial هنوز وجود نداره!مرحله ۲: سبز (نوشتن حداقل کد برای موفقیت)حالا حداقل کد ممکن رو مینویسیم:export const factorial = (n) =&gt; {
  return 120;
};
تست موفق میشه! ولی این کد قاعدتا درست نیست.مرحله ۳: بازنگری (افزایش تستها و بهبود کد)حالا تستهای بیشتری اضافه میکنیم:describe(&#039;factorial&#039;, () =&gt; {
  it(&#039;should calculate factorial of 0&#039;, () =&gt; {
    expect(factorial(0)).toBe(1);
  });

  it(&#039;should calculate factorial of 1&#039;, () =&gt; {
    expect(factorial(1)).toBe(1);
  });

  it(&#039;should calculate factorial of 5&#039;, () =&gt; {
    expect(factorial(5)).toBe(120);
  });
});
حالا برای پاس شدن تستها، کد رو بهبود میدیم:export const factorial = (n) =&gt; {
  if (n === 0 || n === 1) {
    return 1;
  }
  return n * factorial(n - 1);
};
مزایای TDDکیفیت بالاتر: کدی که با TDD نوشته میشه معمولاً باگ کمتری دارهطراحی بهتر: TDD به شما کمک میکنه APIهای بهتری طراحی کنیداعتماد به نفس بیشتر: با تستهای جامع، جرئت تغییر و بهبود کد رو داریدمستندسازی: تستها به عنوان مستندات اجرایی عمل میکننمعایب و چالشهای TDDزمان بیشتر: اول امر زمان بیشتری میبرهمنحنی یادگیری شیب دار: یادگیری TDD نیاز به تمرین دارهبرای همه چیز مناسب نیست: نوشتن تست با این روش، برای بعضی از قسمتهای کد (مثل UI) مناسب نیست.به عنوان یه rule of thumb اگر بخام بگم، تست TDD رو زمانی بنویسید که میدونید برای هر ورودی دقیقا چه خروجی قابل انتظار است، مثلا در validation ها یا state machine ها یا توابع ریاضی.حالا که با TDD آشنا شدیم، بیاید وارد نوشتن اولین تستهامون بشیم!شروع به نوشتن تستهاخب اول از همه اگر پروژه ندارید یه پروژه با روال زیر بسازید و dependency ها رو نصب کنید. اگرم در حال حاضر هر نوع پروژه JavaScript یا typescript دارید، کافیه فقط dependency رو نصبش کنید.npm init -y
npm install -D vitest
حالا فایل زیر رو با عنوان helloWorld.test.ts مثلا ذخیره کنید.import { test, expect } from &#039;vitest&#039;;

test(&#039;is a super simple test&#039;, () =&gt; {
  expect(true).toBe(true);
});
میتونید این تست رو با اجرای npx vitest از خط فرمان اجرا کنید و میبینید که تست پاس میشه. اگر بخوام این فایل رو توضیح بدم:یه تابع به نام test وجود داره که دو تا آرگومان میگیره: 1. یه رشته که نام تست رو نشون میده 2. یه تابع که بدنه تست رو شامل میشهداخل اون تابع، از یه کتابخونه assert برای بیان انتظاراتمون استفاده میکنیم 1. در اینجا، انتظار داریم این دو تا چیز با هم برابر باشن 2. و اونها هستن!یک مثال دیگهحالا بیاید یه مثال واقعیتر بررسی کنیم:test(&#039;another test, but with some logic&#039;, () =&gt; {
  expect(1 + 1).toBe(2);
});

test(&#039;a test with a function&#039;, () =&gt; {
  const add = (a, b) =&gt; a + b;
  expect(add(1, 2)).toBe(3);
});
نکته مهم اینه که، وقتی یک تست مثل فایل بالا مینویسیم، میتونیم (نه اینکه باید!) هر تعداد خواستیم از این (...)test ها داشته باشیم . اینجوری میتونیم مطمئن بشیم هر سناریویی رو پوشش دادیم. وظیفه تست runner (در اینجا npx vitest) اینه که تست ما رو اجرا کنه و مطمئن بشه که همه چیز درست کار میکنه.نحوه کار تستهایه تست فقط به خاطر اینکه شکست نخورده، قبول میشه.این به این معنیه که اگه یه تست شکست بخوره، یعنی یه error انداخته شده. پس وقتی میگیم تست قبول شده، یعنی هیچ errorای ننداخته!تستی که انتظار داریم شکست بخوره با test.failمیتونیم از .test.fails برای تستهایی استفاده کنیم که انتظار داریم شکست بخورن:test.fails(&#039;works with &quot;test&quot; as well&#039;, () =&gt; {
  expect(true).toBe(false);
});
این مثال ساده نشون میده که چطور میتونیم تستهایی بنویسیم که انتظار داریم شکست بخورن.نادیده گرفتن تست با it.skipاگر میخواید یه تست خاص رو موقتاً اجرا نکنید (مثلاً در حال کار روی اون بخش هستید یا تست مشکل داره):it.skip(&#039;this test is temporarily disabled&#039;, () =&gt; {
  expect(someFunction()).toBe(&#039;expected result&#039;);
});
اجرای فقط یه تست با it.onlyاگر میخواید فقط یه تست خاص رو اجرا کنید و بقیه تستها رو نادیده بگیرید (مثلاً وقتی روی یه بخش خاص کار میکنید و میخواید فقط تست مربوط به اون بخش رو ببینید):it.only(&#039;this is the only test that will run&#039;, () =&gt; {
  expect(add(2, 3)).toBe(5);
});
به جای test در vitest میشه it هم نوشت و فرقی ندارند و به کرات به جای هم استفاده میشن، فلذا گیج نشید!تست کد Asyncخب فرض کنیم یه کد async رو بخواهیم تست کنیم. تست زیر به اشتباه قبول میشه، چون تابع بالادست setTimeout یه تابع سنکرونه و منتظر resolve این تایم اوت و رسیدن به assertion نمیشه. (رجوع به مفاهیم async)it(&#039;it will pass, unfortunately&#039;, () =&gt; {
  setTimeout&#40;(&#41; =&gt; {
    expect(&#039;This should fail.&#039;).toBe(&#039;Totally not the same.&#039;);
  }, 1000);
});
خب راه حلش اینه که به سادگی از async/await استفاده کنیم:test(&#039;works with &quot;test&quot; as well&#039;, async () =&gt; {
  const result = await addAsync(2, 3);
  expect(result).toBe(5);
});
مشاهده مقاله کامل در این آدرس:https://farshidev.ir/Post/%D8%AA%D8%B3%D8%AA%E2%80%8C%D9%86%D9%88%DB%8C%D8%B3%DB%8C-javascript-typescript-unit-testموفق باشید.</description>
                <category>فرشید کریمی</category>
                <author>فرشید کریمی</author>
                <pubDate>Thu, 19 Feb 2026 06:34:50 +0330</pubDate>
            </item>
                    <item>
                <title>تست‌نویسی در javascript/typescript — بخش ۱: مقدمات</title>
                <link>https://virgool.io/@m_21642669/%D8%AA%D8%B3%D8%AA-%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D8%AF%D8%B1-javascripttypescript-%E2%80%94-%D8%A8%D8%AE%D8%B4-%DB%B1-%D9%85%D9%82%D8%AF%D9%85%D8%A7%D8%AA-edvrts4nbr1s</link>
                <description>لازمه یه توسعه مسئولیت پذیرانه، نوشتن تسته. تست کردن، اعتماد به نفس ما رو در مورد عملکرد مورد انتظار برنامه‌مون افزایش می‌ده. توی این سری قصد داریم راجع به اصول نوشتن تست کارآمد و لایه های مختلفش صحبت کنیم.مقدمهتست کردن فقط برای پیدا کردن باگ نیست. بلکه تست نوشتن به ما کمک می‌کنه که کد بهتری بنویسیم. وقتی برای تست نوشتن پلن داریم، مجبوریم کدی بنویسیم که سازمان‌یافته‌تر و قابل‌استفاده‌تر باشد. این یه فرآیند دو‌طرفه است:کد خوب &lt;------------------&gt; تست خوبچرا تست نویسی مهمه؟اعتماد به نفس: با تست‌های جامع، جرئت تغییر و بهبود کد رو داریدکیفیت کد: تست‌ها به بهبود کیفیت کد و طراحی کمک می‌کننمستندسازی: تست‌ها به عنوان مستندات اجرایی عمل می‌کننrefactoring ایمن: با تست‌های مناسب می‌تونید کد رو重构 کنید بدون ترس از شکستن ویژگی‌هاکاهش باگ: تست‌ها به شناسایی و جلوگیری از باگ‌ها کمک می‌کننچالش‌های پیش رومنحنی یادگیری: تست نویسی نیاز به تمرین و تجربه دارهزمان و هزینه: نوشتن تست زمان و هزینه داره، اما سرمایه‌گذاری ارزشمندیهنگهداری تست‌ها: با تغییر کد، تست‌ها هم نیاز به به روز رسانی دارنتعادل: باید تعادل بین نوشتن تست و توسعه ویژگی‌ها برقرار کردروش‌های تستما در این سری، سه متد رایج تست رو بررسی خواهیم کرد:تست واحد (unit test)تست یکپارچگی (integration test)تست نهایی (e2e test)تست واحد (Unit Test)تست واحد، کوچک‌ترین قسمت برنامه‌مون رو تست می‌کنه. یه تابع یا متد را به طور ایزوله بررسی می‌کنیم که انتظار داریم چطوری کار کنه. عموما این نوع تست‌ها سریع و جمع‌وجور هستند.تست یکپارچگی (Integration Test)تست یکپارچگی، چند تا از قسمت های برنامه‌مون رو با هم تست می‌کنه. مثلاً فرض کنید یه بخش از برنامه‌ ما یه API صدا می‌زنه و نتیجه رو پردازش می‌کنه و یا چندتا هوک و کامپوننت react ای در یک کامپوننت رو شبیه‌سازی می‌کنیم تا از عملکردشون کنار هم مطمئن بشیم.تست نهایی (E2E Test)تست نهایی (end-to-end)، کل برنامه‌ رو از دید کاربر نهایی تست می‌کنه. یعنی ما شبیه‌سازی می‌کنیم که کاربر چطور با برنامه‌مون تعامل داره. مثلاً کاربر روی دکمه‌ای کلیک می‌کنه، فرم رو پر می‌کنه و نتیجه رو می‌بینه.پیش از شروعابزارهای استفاده‌شدهدر این سری از ابزارهای شناخته‌شده، به‌روز و پرکاربرد استفاده خواهیم کرد:Vitest - یه گزینه مدرن و سریع برای تست unit و integration و جایگزین JestTesting Library - یه کتابخونه با کلی ابزار مفید برای تست DOMJSDOM یا HappyDom - یه کتابخونه سریع برای شبیه‌سازی محیط ‌DOM در nodePlaywright - برای تست E2Eراجع به اینکه کدوم ابزار رو کی استفاده می‌کنیم در بخش های مربوطه توضیح می‌دیم.پیش‌نیازهاآشنایی اولیه با javascript یا typescriptآشنایی با git, npm و node</description>
                <category>فرشید کریمی</category>
                <author>فرشید کریمی</author>
                <pubDate>Thu, 19 Feb 2026 06:31:51 +0330</pubDate>
            </item>
                    <item>
                <title>استفاده از zustand برای بهبود مدیریت state ها</title>
                <link>https://virgool.io/@m_21642669/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-zustand-%D8%A8%D8%B1%D8%A7%DB%8C-%D8%A8%D9%87%D8%A8%D9%88%D8%AF-%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-state-%D9%87%D8%A7-auvbmtyiqduu</link>
                <description>وقتی صحبت از مدیریت stateها در اپلیکیشنهای react ای میشه نمیشه یه نسخه برای همه اپلیکیشنها پیچید، بعضی وقت ها stick شدن به همون امکانات react مثل Context API جوابه و بعضی وقتها نیاز به کتابخونه هایی مجزا برای مدیریت stateها داریم.درباره اینکه استراتژی مناسب برای هر موضوع چیه، امیدوارم بتونیم توی یه پست مجزا راجع بهش صحبت کنیم. به عنوان یه rule of thumb باید بگم که این دو نکته می تونه به شما بگه شاید وقتش باشه که به یک کتابخونه مدیریت state مجزا فکر کنید.تعداد زیاد state ها در Context APIنرخ بالای بروزرسانی state ها در کامپوننتالبته core react دائما در حال توسعه است و مواردی مثل react compiler می تونه تا حدودی شرایط رو تغییر بده.حالا بریم سر داستان خودمون. zustand قطعا توی دسته کتابخونه های مجزا از core react برای مدیریت stateها قرار می گیره. کار با zustand خیلی راحت و مشابه react عه، اول از همه بگذارید راجع به فلسفه کارکردی zustand یکم صحبت کنیم و اینکه چجوری داره کار میکنه.فلسفه عملکردی zustandوقتی شما با zustand یک store در جایی می سازی در حقیقت در run-time جاوااسکریپت یه محدوده ای میسازی که داخلش چیزهایی که میخوای رو ذخیره میکنی.اول بگم lifecycle این store در وهله اول کاملا به run-time مرورگر شما بستگی داره یعنی اگر صفحه مرورگر رو reload کنید قاعدتا این store پاک میشه مگر اینکه جای دیگه ای هم persist بشه که موضوع بحث ما فعلا نیست. همونطور که توی شکل بالام مشخصه اپلیکیشن شما هر حرکتی بزنه دخلی(!) به این store به طور معمول نداره چون space یا فضای حافظه و run-time شون جداست.حالا از این ببعدش جالب میشه، شما وقتی zustand رو به طور مثال در برنامه react تون استفاده میکنید یه wrapper ای از جنس stateهای react دورش ایجاد میشه که فرآیندهای آپدیت و rendering در react بدین وسیله handle میشه.شکل زیر تقریبی از چیزی است که اتفاق میافته. به عبارتی برای اینکه react برای این که بتونه فرآیندهای rendering رو برعهده بگیره نیاز به چیزی داره که براش معنا و مفهوم داشته باشه که همون stateهاست. حالا ما هربار که useStore رو استفاده کنیم(بعدا خواهیم گفت)، در حقیقت کنترل re-render و render رو برعهده میگیریم.اولین گام zustand - ساخت storeدر کتابخونه zustand برای ساختن state کافیه متد create رو صدا بزنید:import { create } from &quot;zustand&quot;;
حالا store رو populate میکنیم:export const useTasksStore = create&lt;TasksState&gt;((set) =&gt; ({
    tasks,
    setTasks: (arg: Task[] | ((tasks: Task[]) =&gt; Task[])) =&gt; {
        set((state) =&gt; {
            return {
                tasks: typeof arg === &quot;function&quot; ? arg(state.tasks) : arg,
            };
        });
    },
    currentView: &quot;list&quot;,
    setCurrentView: (newView: TasksView) =&gt; set({ currentView: newView }),
    currentFilter: &quot;&quot;,
    setCurrentFilter: (newFilter: string) =&gt; set({ currentFilter: newFilter }),
}));
همونطور که میبینید تابع create یه تابع به عنوان آرگومان خودش میگیره. این تابع یک خودش یه آرگومان به نام set داره که میتونیم ازش برای مقداردهی موارد داخل store مون استفاده کنیم. (آرگومان get هم داره که بعدا میگیم به چه دردی میخوره)طبعا ما می تونیم state ها رو به صورت پیچیده تری آپدیت کنیم و دستمون بازه اینجا. به این سبک partial update هم میگن.setCurrentView: (newView: TasksView) =&gt; set({ currentView: newView, tasks: [] }),
همچنین تابع بالا یه آرگومان دوم هم می گیره که باهاش می تونیم کل store رو replace کنیم، مثلا در مثال زیر store مون رو می تونیم با clear ریست کنیم. البته در استفاده ازش با دقت عمل کنید چون می تونه کل store تون رو wipe کنه.const initialState = {
  user: null,
  loggedIn: false,
};

const useStore = create((set) =&gt; ({
  ...initialState,
  clear: () =&gt; set(initialState, true),
}));

خب حالا بریم این custom hook ای که ساختیم رو استفاده کنیم. منظورم همین store هست که با useStore ایجاد شده است.برای این کار روش های متنوعی وجود داره و خیلی راحت میتونید انتخاب اشتباهی رو صورت بدید و اوضاع رو خرابش کنید. ما در ادامه خیلی گاماس گاماس با هم پیش میریم تا معایب و مزایای هر روش رو به خوبی خودتون متوجه بشید.استفاده از zustand در کامپوننتاستفاده از الگوی atmoic تا ابد!استفاده از zustand بدین شکل که state ها رو در متغیرهای مجزا استخراج کنیم(atomic pattern)، همیشه جوابه و توصیه خود zustand هم در غالب مواقع همین روشه.const currentView = useTasksStore(state =&gt; state.currentView);
const tasks = useTasksStore(state =&gt; state.tasks);
const currentFilter = useTasksStore(state =&gt; state.currentFilter);

همونطور که واضحه در این حالت و هربار باید explictly بگیم چی ها رو می خواهیم. یعنی باید از selector استفاده کنیم، مشابه اونچه در غالب state manager ها مثل redux هم داشتیم.اینجوری دقیقا میگیم چیارو می خواهیم و فقط state مربوط به همونا میاد توی کامپوننت مون و هربار که فقط این state عوض بشه کامپوننت ما rerender میشه. یعنی میشه با تقریبی اینو معادل این دونست برای درک بهتر وگرنه در واقعیت کمی پیچیده ترهconst [currentFilter] = useState({&quot;Current State&#039;s Value in the Store&quot;});
.
.
خب دیگه حالا هرچی توی store عوض بشه تا وقتی currentFilter عوض نشه این state موجبات rerender کامپوننت مون رو فراهم نمی کنه و این درسته!خواندن store به صورت گرتره ایمی تونیم به روش زیر state مون رو از store بخونیم که خب اتفاقا کار هم می کنه.const { currentFilter } = useTasksStore();
در این خط، کتابخونه zustand به طور پیشفرض در جواب useTasksStore کل store رو برمی گردونه که در واقع اگر به فلسفه zustand برگردیم یعنی stateهای کل store در این کامپوننت قرار داده میشن و این یعنی اگر هرکدوم از اون state ها آپدیت بشن این کامپوننت rerender خواهد شد. دقت کنید در این مورد object destructring هم با این که انجام شده ولی تاثیری نداره.این اتفاق شبیه همون چیزی که توی Context API خود react رخ میده، فلذا اینگونه استفاده با هدف zustand در غالب مواقع همخوانی نداره.خب تا همینجا کافیه که بتونید توی کامپوننتهاتون از zustand استفاده کنید و کنترل rendering رو راحتتر داشته باشید. از اینجا ببعد ما به این میپردازیم که چگونه از zustand به صورت هوشمندانهتری استفاده کنیم و اینم یادتون نره که هرجا شک کردید که کدوم راه درستتره just stick to atomic pattern که همیشه جوابه!استفاده از zustand طبیعتا هیچ محدودیتی در عدم استفاده از کتابخونههای دیگه مدیریت state برای شما ایجاد نمی کنه و می تونید توی یه پروژه redux ای یا با context API به کارش بگیرید، اگر لازم بود.در پایان این بخش اگر بخواهیم به صورت مرحله به مرحله آن چه در selectorهای zustand اتفاق میفته رو بگیم، این میشه:با هر selector در حقیقت zustand اون کامپوننت رو در store خبردار یا subscriber قرار میدهکه این یعنی با هر set در store:کتابخانه zustand میاد selector رو اجرا میکنهمقدار قبلی حاصل از برآورد این selector با مقدار حاصل از بخش یک مقایسه میشهاگر تغییری رخ داده بود، کامپوننت re-render میشهاگرم رخ نداده بود که هیچی به هیچی!استفاده هوشمندانه تر از zustandاول از همه با یه مثال react ای بگم چه مواقع الگوی atomic کد مارو یه جوری میکنه!import { create } from &quot;zustand&quot;;

type State = {
    count: number;
    user: { name: string; email: string };
    increment: () =&gt; void;
};

export const useTestStore = create&lt;State&gt;((set) =&gt; ({
    count: 0,
    views: 1,
    user: { name: &quot;Marco&quot;, email: &quot;marco@example.com&quot; },
    increment: () =&gt; set((state) =&gt; ({ count: state.count + 1 })),
}));
حالا استفاده ازشimport { useTestStore } from &#039;./store&#039;

export default function Example1() {
  const user = useTestStore(state =&gt; state.user)
  const count = useTestStore(state =&gt; state.count)
  const increment = useTestStore(state =&gt; state.increment)

  return (
    &lt;div&gt;
      &lt;p&gt;Count: {count}&lt;/p&gt;
      &lt;button ={increment}&gt;User: {user.name}&lt;/button&gt;
    &lt;/div&gt;
  )
}
همانطور که می بینید اگر تعداد بیشتری state داشته باشیم یه جورایی کلی باید چیز تکراری و boilerplate بنویسیم. آیا راه بهتری هم هست؟ بله!import { useTestStore } from &#039;./store&#039;

export default function Example1() {
  const { user, count, increment } = useTestStore((state) =&gt; ({
    user: state.user,
    count: state.count,
    increment: state.increment,
  }));

  return (
    &lt;div&gt;
      &lt;p&gt;Count: {count}&lt;/p&gt;
      &lt;button ={increment}&gt;User: {user.name}&lt;/button&gt;
    &lt;/div&gt;
  )
}
گیرش کجاست؟ فرض کنید در یک کامپوننت دیگه داشته باشیم.import { useTestStore } from &#039;./store&#039;

export default function Example2() {
  const {user, views} = useTestStore(state =&gt; ({views:state.views, user:state.user}))

  return (
  		&lt;div&gt;
  		&lt;p&gt;{user}&lt;/p&gt;
       &lt;p&gt;User views: {views}&lt;/p&gt;
       &lt;/div&gt;
  )
}
حالا اگر به طور مثال از increment در Example1 استفاده کنیم یعنی روی button کلیک کنیم، این خط (سلکتور) یکبار دیگر اجرا خواهد شد تا از تغییرات احتمالی مطلع شود. (بالاتر گفته بودیم که هر selector یک subscriber است)const { user, views } = useTestStore((state) =&gt; ({
    views: state.views,
    user: state.user,
}));
طبق تعریف increment، فقط count در store عوض میشود. سپس این خط یکبار دیگر ارزیابی شده و آبجکت دیگری دقیقا با همین مقادیر تولید خواهد کرد(چون چیزی عوض نشده است). حالا چون دو آبجکت رفرنس یکسانی ندارد، در نتیجه این کامپوننت بیخودی رندر مجدد می شود.برای حل این مشکل باید یه جوری به zustand بگیم که آقا ما نمی خواهیم دو تا آبجکت رو با هم از نظر رفرنس مقایسه کنی و فقط همین که مقادیرش عوض بشه برامون مهمه. برای این کار از مفهوم shallow استفاده می کنیم.مشاهده مقاله کامل در این آدرس:https://farshidev.ir/Post/%E2%80%8Czustand-react-smart-state-managmentموفق باشید.</description>
                <category>فرشید کریمی</category>
                <author>فرشید کریمی</author>
                <pubDate>Thu, 19 Feb 2026 06:26:18 +0330</pubDate>
            </item>
                    <item>
                <title>Layers و Stacking Context چی هستند و چجوری می‌تونن Performance سایت‌مون رو بهتر کنند؟</title>
                <link>https://virgool.io/@m_21642669/layers-%D9%88-stacking-context-%DA%86%DB%8C-%D9%87%D8%B3%D8%AA%D9%86%D8%AF-%D9%88-%DA%86%D8%AC%D9%88%D8%B1%DB%8C-%D9%85%DB%8C-%D8%AA%D9%88%D9%86%D9%86-performance-%D8%B3%D8%A7%DB%8C%D8%AA-%D9%85%D9%88%D9%86-%D8%B1%D9%88-%D8%A8%D9%87%D8%AA%D8%B1-%DA%A9%D9%86%D9%86%D8%AF-lpb9ds7unzxq</link>
                <description>مقدمهدو مفهوم Stacking context و Layers در فرآیند تبدیل کدهای ما به صفحات وب در مرورگر معنا پیدا می‌کنند. این دو مفهوم خیلی شبیه هم هستند و حتی بعضی جاها اشتباها به جای هم به کار میرن اما تفاوت دارند. دونستن این تفاوت بهمون کمک می‌کنه که CSS ای بنویسیم که به سایت با کیفیت‌تری منتج بشه!از اونجایی که گفتم فرآیند تبدیل کد ما به صفحات وب، لازمه تا یک بار این فرآیند رو مرور کنیم و اختصارا بگیم که این دو مفهوم در کدوم لایه از این فرآیند خودشون رو نشون می‌دن.فرآیند رندرینگ مرورگروقتی یه صفحه وب رو باز می‌کنید، مرورگر چند مرحله اصلی رو طی می‌کنه تا کدهای شما رو به یه صفحه قابل مشاهده تبدیل کنه:۱. ساخت DOM (Document Object Model)وقتی مرورگر کدهای HTML شما رو می‌خونه، یه ساختار درختی به نام DOM می‌سازه. این درخت شامل تمام المان‌های HTML صفحه شما می‌شه، از &lt;html&gt; تا آخرین &lt;div&gt; یا &lt;span&gt;. هر المان یه node در این درخت محسوب می‌شه.۲. ساخت CSSDOM (CSS Object Model)همزمان با ساخت DOM، مرورگر کدهای CSS رو هم پردازش می‌کنه و یه ساختار درختی دیگه به نام CSSDOM می‌سازه. این درخت شامل تمام استایل‌ها و قوانین CSS می‌شه که مشخص می‌کنه هر المان چجوری باید نمایش داده بشه.۳. ترکیب DOM و CSSDOM - درخت رندر (Render Tree)بعد از ساخت DOM و CSSDOM، مرورگر این دو درخت رو با هم ترکیب می‌کنه و یه درخت رندر ایجاد می‌کنه. این درخت فقط شامل المان‌هایی می‌شه که قابل نمایش هستند (مثلا المان‌های با display: none در این درخت وجود ندارند).۴. محاسبه Layout (Reflow)در این مرحله، مرورگر موقعیت و اندازه دقیق هر المان رو در صفحه محاسبه می‌کنه. این فرآیند به عنوان reflow یا layout شناخته می‌شه. مرورگر از اطلاعات درخت رندر استفاده می‌کنه تا بفهمه هر المان کجا باید قرار بگیره و چقدر فضا اشغال کنه.۵. Paint (رنگ‌آمیزی)بعد از اینکه موقعیت و اندازه المان‌ها مشخص شد، مرورگر شروع می‌کنه به رنگ‌آمیزی یا paint کردن المان‌ها. در این مرحله، رنگ‌ها، تصاویر، متن‌ها و سایر ویژگی‌های بصری روی صفحه کشیده می‌شن.۶. Composition (ترکیب لایه‌ها)در مرحله آخر، مرورگر لایه‌های مختلف رو با هم ترکیب می‌کنه تا صفحه نهایی رو نمایش بده.توصیه می‌کنم یه بار به این مقاله در وبسایت کروم مراجعه کنید. چون داخلش این فرآیند رو به شکل تصویری خیلی خوب نشون داده.نکات مهماز بین مراحل فوق، همگی به جز Compostion کاملا در CPU انجام می ‌شوند.امور مربوط به ایجاد Stacking Context در بخش Paint رخ می‌دهد. (جلوتر می‌رسیم)امور مربوط به Layers (جلوتر می‌رسیم که چی هستن) در بخش Composition رخ می دهد. (عمدتا در GPU)زمانبر ترین بخش این فرآیندها، بخش Layout یا Reflow است، چون باید x,y یک المان یا مختصاتش رو CPU دربیاره و برای این فرآیند باید تمام المان‌های توی صفحه رو درنظر بگیره.ذکر این نکته هم لازمه که، چنانچه سیستمی GPU نداشته باشه (که دیگه اینروزا خیلی بعیده) قضیه hand-off میشه به همون CPU مون!بنابراین اگر حرکاتی(!) بزنیم که Reflow رخ نده، می‌تونیم انتظار سرعت و عملکرد بهتری در وبسایتمون داشته باشیم. منظورمون از حرکات هم صرفا تغییر css مونه.البته Reflow لازم و ضروریه اما یه وقت‌هایی واسه یه چیز بیخودی و دائما در حال انجام (مثل انیمیشن‌ها) ما اشتباها موجبات Reflow رو فراهم می‌کنیم (در حالیکه می‌تونیم نکنیم) و اینجوری سایتمون کند میشه و بعضا هنگ می‌کنه.چه حرکاتی نیازی به reflow ندارند؟اگر بخوایم براش یه لیست درست کنیم، قطعا به خاطر نمیشه سپرد و اصلا کار جالبی هم نیست!فقط کافیه این rule of thumb رو بخاطر بسپارید:هر تغییر CSS ای که ابعاد و موقعیت x,y یک المان و همسایه‌هاش رو عوض نکنه، موجب reflow نمیشه.خب دیگه خودتون می تونید یه لیست درست کنید، کارهایی مثل تغییر color و background و opacity تنها نمونه‌هایی از این لیست هستند.مثال عملی: انیمیشن با Reflow و بدون Reflowیه انیمیشن ساده رو با دو روش زیر انجام بدیم یکی با مارجین یکی با ترنسفورم. اولی یه nightmare برای مرورگره و دومی یه چیزه خیلی سریع و مناسب.روش اول: استفاده از margin (دردسرساز!)&lt;div class=&quot;container&quot;&gt;
  &lt;div class=&quot;box bad-animation&quot;&gt;Animation with margin&lt;/div&gt;
&lt;/div&gt;
.box {
  width: 100px;
  height: 100px;
  background: blue;
  margin-top: 10px;
}

.bad-animation:hover {
  margin-top: 110px; /*  This cause reflow!  */
  transition: margin-top 0.3s ease;
}
روش دوم: استفاده از transform (بهینه!)&lt;div class=&quot;container&quot;&gt;
  &lt;div class=&quot;box good-animation&quot;&gt;Animation with transform&lt;/div&gt;
&lt;/div&gt;
.box {
  width: 100px;
  height: 100px;
  background: green;
  margin-top: 10px;
}

.good-animation:hover {
  transform: translateY(100px); /* This isn&#039;t cause reflow! */
  transition: transform 0.3s ease;
}
توضیح:در روش اول، با تغییر margin-top، مرورگر مجبور هست تمام المان‌های بعدی رو مجددا محاسبه کنه (reflow)در روش دوم، transform فقط المان رو در Stacking context جداگانه‌ای حرکت میده و نیازی به محاسبه مجدد موقعیت سایر المان‌ها ندارهبریم سراغ Stacking Contextمقدمه: حالت چینش normal flow چیه؟فرض کنید یه فایل HTML مانند فایل زیر دارید. تمامی المنت‌ها در این فایل، در normal flow زیست می کنند.&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;Simple HTML Page&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;Hello, World!&lt;/h1&gt;
    &lt;p&gt;This is a simple HTML page with no styles or JavaScript.&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
مفهوم normal flow در مرورگر: یعنی المان های از نوع block در زیر هم به صورت عمودی قرار می گیرند و المان های از نوع inline به صورت افقی در کنار هم. تصویر زیر:تمام المنت‌هایی که در HTML داریم مثل div, p, a, article, و غیره همگی به طور پیشفرض براساس normal flow توسط مرورگر چیده می‌شوند، مگر اینکه با Stacking Context آن‌ها رو از normal flow خارج کنیم!تعریف ‌Stacking Contextاگر با واژه stack آشنا نیستید باید بگم، stack مشابه طبقات یک کیک است که روی هم قرار می‌گیرند و وقتی می‌خواهیم کیک بخوریم قاعدتا اون طبقه بالایی رو اول برمی‌داریم. به عبارت دیگر آخرین (روترین) لایه روی کیک، اولین لایه‌ای است که باید برداریم. (لطفا تصورش کنید!)حالا Stacking Context در مرورگر طبق تعریف سایت MDN می‌شود:اگر ساختار چینش المان ها در صفحه HTML را در یک صفحه سه بعدی در نظر بگیریم، به محور Z و نحوه قرارگیری المان ها در آن stacking context می گویند.چجوری stacking context ایجاد کنیم؟هر کدام از element های زیر می‌توانند منجر به ایجاد stacking context جدید شوند:المنت (&lt;html&gt;)المنتی با مقدار position برابر absolute یا relative و مقدار z-index غیر از autoالمنتی با مقدار position برابر fixed یا stickyالمنتی با مقدار container-type برابر size یا inline-sizeالمنتی که یک flex item است با مقدار z-index غیر از autoالمنتی که یک grid item است با مقدار z-index غیر از autoالمنتی با مقدار opacity کمتر از 1المنتی با مقدار mix-blend-mode غیر از normalالمنتی با هر یک از خواص زیر با مقداری غیر از none:transform (مثالی که بالاتر زده بودیم مثلا همین رو فقط داشت)scalerotatetranslatefilterbackdrop-filterperspectiveclip-pathmask / mask-image / mask-borderمشاهده کامل مقاله درhttps://farshidev.ir/Post/layers-and-stacking-contextموفق باشید.</description>
                <category>فرشید کریمی</category>
                <author>فرشید کریمی</author>
                <pubDate>Thu, 19 Feb 2026 06:18:18 +0330</pubDate>
            </item>
                    <item>
                <title>استفاده از bootstrap در Reactjs و Nextjs و Typescript</title>
                <link>https://virgool.io/@m_21642669/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-bootstrap-%D8%AF%D8%B1-reactjs-%D9%88-nextjs-%D9%88-typescript-afct5fjeje7u</link>
                <description>در Reactjs: (با Typescript یا بدون آن)نصب اولیه:npm i bootstrapدو دستور زیر را به index.js می افزاییم:import &amp;quotbootstrap/dist/js/bootstrap.min.js&quot;
import &#039;bootstrap/dist/css/bootstrap.min.css&#039;;در Nextjs: (بدون Typescript)نصب اولیه:npm i bootstrapدستورات زیر را به app.js_ می افزاییم: (چون در nextjs روی سمت سرور صفحه ساخته می شود و آنجا document یا window نداریم، بایستی ایمپورت bootstrap.js رو در زمانی که صفحه روی مرورگر رندر شد، انجام دهیم)import &#039;bootstrap/dist/css/bootstrap.min.css&#039;;
import {useEffect} from &#039;react&#039;;

useEffect(() =&gt; { 
import(&amp;quotbootstrap/dist/js/bootstrap.min.js&amp;quot);
}, []);در Nextjs: (با Typescript)تنها تفاوت نسبت به حالت بدون Typescript در نحوه نوشتن useEffect است:useEffect(() =&gt; {
typeof document !== undefined ? require(&#039;bootstrap/dist/js/bootstrap&#039;): null 
}, [])البته اگر خواستید می تونید از react-bootstrap هم استفاده کنید که چالش های بالا رو نداشته باشید.</description>
                <category>فرشید کریمی</category>
                <author>فرشید کریمی</author>
                <pubDate>Wed, 25 May 2022 15:19:07 +0430</pubDate>
            </item>
                    <item>
                <title>ساخت پروژه API در React با Typescript</title>
                <link>https://virgool.io/Solidity/%D8%B3%D8%A7%D8%AE%D8%AA-%D9%BE%D8%B1%D9%88%DA%98%D9%87-api-%D8%AF%D8%B1-react-%D8%A8%D8%A7-typescript-j2k6rmookqtx</link>
                <description>پروژه کار با API ساده در React را قدم به قدم با Typescript انجام می دهیم.ما در این نوشته یک برنامه API ساده در React را به کمک Typescript می سازیم. Typescript به نوعی یک Wrapper روی Javascript است که به ما قدرت بیشتری می دهد. اصلی ترین ویژگی این اصطلاحا زبان برنامه نویسی، strict type بودن متغیر ها می باشد. به عبارت دیگر از آنجا که در Javascript ما type نداریم به کمک این زبان می توانیم type ها را به صورت صریح مشخص نموده و از خطاها جلوگیری کنیم.خب برو بریم!برای این کار اول با npx یک پروژه می سازیم. همانطور که توجه می کنیم تمپلیت پیش فرضی که به create-react-app گفتیم تا برای ما بسازه به زبان tsx (typescript) استnpx create-react-app typescript-apiapp --template typescriptخب اگر در پروژه ای که ایجاد شده، دقت کنید. متوجه می شوید تمام فایل هایی که در یک پروژه react با پسوند js بود، تبدیل به پسوند tsx شده اند. همچنین برای زیباتر شدن پروژه از Bootstrap نیز استفاده خواهیم نمود بنابراین آن را با دستور زیر نصب می کنیم.npm i bootstrapبرای استفاده از bootstrap در صورت تمایل می توانید دو خط زیر رو به ابتدای index.tsx تون اضافه کنید.import &amp;quotbootstrap/dist/css/bootstrap.min.css&amp;quot
import &amp;quotbootstrap/dist/js/bootstrap.min.js&amp;quotخب فایل App.tsx رو باز می کنیم و تمام محتویات اون رو پاک می کنیم تا به شکل زیر در بیاد.خیلی ریکلس حالا توی src یک پوشه به نام components ایجاد می کنیم و دو فایل Header.tsx و Header.css رو در اون قرار می دهیم.کد Header.js را به صورت زیر می نویسیم. در این کد type کامپوننت Header را از نوع React.FunctionComponent مشخص کردیم که یک type تعریف شده در React می باشد. توجه کنید که کامپوننتی که از این فایل export می شود هم همین Header است. همچنین به وسیله generic ها در زبان tsx باید type ورودی این کامپوننت هم با Interface ها تعریف شود که در اینجا IHeaderProps می باشد که چون ورودی برای این کامپوننت نیاز نداریم، خالی می گذاریم.همچنین App.tsx را نیز به صورت زیر تغییر می دهیم.به زودی از این سایت اطلاعات کاربران را دریافت می کنیم و نمایش می دهیم، اما قبل از آن نیاز داریم تا type داده های دریافتی از API را به صورت صریح مشخص کنیم. برای اینکار پوشه به نام models در پوشه src ایجاد می نماییم و فایل note.model.ts را مطابق زیر در آن ایجاد می کنیم.export interface note {
 id: string,
  title:string,
  body:string
};در ادامه ما نیاز به کامپوننتی داریم تا note ها را به ما نشان دهد و بتونیم اون رو در Header مون بگذاریم. برای این کار کامپوننت ListNotes.tsx را ایجاد می کنیم. این کامپوننت هم مشابه کامپوننت Header تعیین type شده است. برای ورودی این کامپوننت ورودی notes را تعیین کردیم که باید با نام موجود در interface یکسان باشد. به کمک interface می توانیم type این ورودی را تعیین کنیم.حالا تغییرات لازم در App.tsx را انجام می دهیم تا خروجی کامپوننت بالا به کاربر نشان داده شود. نکات لازم به ذکر این است که ما اولا props ای که بوسیله useState آن را نگهداری می کنیم، به کامپوننت ListNotes دادیم. همچنین type متغیر notes را از نوع model ای که تعریف کردیم، تعیین کردیم.خب خسته نباشید، قلنج انگشتاتون رو بشکنید تا بریم سراغ ادامه کار.حالا اطلاعات رو از API می گیریم و نمایش می دهیم. این کار رو در App.tsx و به کمک useEffect و فقط در اولین رندرینگ انجام می دهیم.خروجی بدین صورت خواهد بود.خب می خواهیم در انتها یک ویژگی دیگه هم اضافه کنیم که آیتم های بالا را بتوان حذف نمود. برای این کار اول باید توجه داشته باشیم که متدی که قدرت تغییر notes را دارد setNotes است که در App.tsx است، بنابراین آن را به ListNotes پاس می دهیم.خب حال تغییرات اصلی را در ListNotes.js می دهیم. اول در UI یک دکمه ایجاد می کنیم و البته key لازم را به هر آیتم می دهیم. وظیفه دکمه پاس دادن id آیتم به متد حذف کننده است.در متد حذف کننده به وسیله filter آیتمی که id آن موافق id مدنظر باشد را حذف می کنیم. همچنین چون به props های ListNotes تابع setNotes را نیز افزودیم باید در interface آن را معرفی کنیم.خسته نباشید! امیدوارم براتون مفید واقع شده باشه و من خوب توضیح داده باشم. ممنون میشوم اشکالی چیزی بود بهم بگید.ضمنا سورس کامل پروژه در این آدرس می باشد.</description>
                <category>فرشید کریمی</category>
                <author>فرشید کریمی</author>
                <pubDate>Thu, 10 Mar 2022 17:04:35 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش React Router ورژن 6</title>
                <link>https://virgool.io/Solidity/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-react-router-%D9%88%D8%B1%DA%98%D9%86-6-a9z7bvdcqpku</link>
                <description>آموزش قدم به قدم آخرین ورژن React Router با یک پروژه سادهاز انتشار ورژن 6 کتابخونه React Router حدود 5 ماهی می گذره، و این ورژن ویژگی های کاربردی زیادی نسبت به ورژن 5 داره که ما در این نوشته با ساختن یک پروژه قدم به قدم یادشون می گیرم.خب گام اول مثل همیشه ساخت پروژه اولیه مون هستش‍‍‍‍npx create-react-app router-v6خب آخرین ورژن router رو در پروژه نصب می کنیمnpm install react-router-domخب همونطور که می دونید هر پروژه Reactjs که از روند بالا تولید میشه، کلی بخش غیرقابل استفاده برای تازه کارها داره که حذفشون می کنیم.(اینو بگم که من از ویرایشگر Atom تحت Lubuntu استفاده می کنم که البته برای شما می تونه هر چیز دیگری باشه)حالا فایل index.js مون رو هم خلوت می کنیم تا بدین شکل بشهفایل App.js مون رو نیز هم!الان همچین چیزی در برنامه مون داریمدر پوشه src یک پوشه به نام components ایجاد کرده و فایل Home.js با محتویات زیر رو در اون ایجاد می کنیم.حالا فایل App.js رو ویرایش می کنیم تا حاوی Home.js شود، باید به این نکته اشاره کنم که در ورژن ششم، Switch با Routes تعویض شده است.من برای نوشتن UI از bootstrap و sass کمک می گیرم که البته ارتباطی با روند پروژه نداره و برای سادگی می باشد. برای استفاده ازون من از روش زیر توی پروژه نصبش می کنم و بعد در کامپوننت مدنظرم import اش می کنم.npm install bootstrap sassیه کامپوننت جدید به نام Courses.js اضافه می کنیم.حالا در App.js مون دو تا Route ایجاد می کنیم. اولی به Courses اشاره می کند به طور معمول(مسیر courses). دومی از ویژگی جدیدی به نام Navigate استفاده می کند که ما از طریق مسیر apps به همان مسیر courses می رسیم. (کاربرد آن در ادامه واضح تر خواهد شد.)حالا در صورتی که به localhost:3000/courses یا localhost:3000/apps برویم با صفحه زیر مواجه می شویم.حالا دو کامپوننت جدید ایجاد می کنیم که درون کامپوننت Courses آن ها را در ادامه نشان خواهیم داد. این دو کامپوننت AllCourses.js و Bundles.js  می باشند. برای شفافیت بگم که Bundles یک کامپوننت در کنار کامپوننت AllCourses است که می تواند موارد دلخواه دیگری در آن قرار بگیرد و AllCourses هم قرار است تمامی درس ها را نشان دهد و Courses هم عوض می کنیم به زودی.حالا در App.js به route درس ها، دو route می افزاییم. این کار باعث می شود که مسیر دو route جدید در امتداد مسیر درس ها یعنی courses/ باشد.حالا Courses.js رو ویرایش می کنیم تا حاوی دو button باشد که ما رو AllCourses و Bundles ببره. برای لینک دادن به اون ها از Link و برای نمایش محتواشون از Outlet استفاده می کنیم.حاصل بدین صورت خواهد بود.خب خسته نباشید :) . تا اینجا یک Routing ساده صفحات رو انجام دادیم.حالا فرش کنید که می خواهیم روی هر درس که کلیک شد، اطلاعاتی درباره اون درس به کاربر نمایش داده بشه و اون رو در یک آدرس مجزایی نشان دهد مثلا جزئیات درس CSS در مسیر زیر:localhost:3000/courses/allcourses/CSSخب برای اینکار با توجه به relative بودن مسیر، اون رو در route اصلی در App.js می افزاییم. اگر به مسیر SingleCourse دقت کنید، متوجه می شوید که مسیر id: می باشد. این یعنی مسیر دینامیک توسط برنامه خودمون تعیین می شود و می تونه هر چیزی باشه. برای اینکه خود SingleCourse بفهمد که در چه مسیری می باشد، جلوتر روشی با useParams گفته می شود.حالا تغییرات لازم به کد AllCourses.js می دهیم. لیست درس ها را به کمک map می سازیم. به متد map دقت کنید. اولا از آنجا که ورودی string است پس به وسیله template literals ما مسیر خودمون رو تولید کردیم.  فرق این کد با کد قبلی این است که Link به NavLink تبدیل شده است. تفاوت اصلی NavLink این است که وقتی روی آن کلید می شود، به طور خودکار کلاس active. برای آن فعال می شود و بدین وسیله ما در کد css مون می تونیم براش ویژگی خاصی تعیین کنیم. فقط همین!  اگر حال نمی کنید همون Link رو بگذارید باشه. نهایتا هم با Outlet محتوای اون مسیر رو نشون می دهیم.خب توی App.js محتوای مسیرهای فوق رو به SingleCourse متصل کردیم حالا SingleCourse.js رو می سازیم. برای دسترسی به id که در واقع همون مسیر ماست، از هوکی به نام useParams استفاده می کنیم و اطلاعات را نشان می دهیم.خب حالا نکته دیگری رو با هم تمرین می کنیم  و اون pass کردن دیتا بین دو کامپوننت است. در ورژن 6 router این کار را می توان هم با هوک useNavigate و هم با خود Link انجام داد. ما هر دوی این روش ها رو تست می کنیم.به این منظور، در SingleCourse ما بخشی رو درنظر می گیریم که اطلاعات را به کامپوننتی به نام Dashboard برای ما منتقل کند که در یک route جداگانه می باشد. بنابراین اول Dashboard را در App.js معرفی می کنیم.حالا تغیرات لازم را در SingleCourse.js داده که همانطور که گفتیم قرار است اطلاعات را برای ما منتقل کند از دو روش. برای انتقال از طریق useNavigate از تگ &lt;a&gt; استفاده کردیم که البته می توانست button هم باشد یا هر چیزی دیگری و از Link هم برای انتقال داده به کامپوننت Dashboard استفاده کردیم.خب حالا در کامپوننت Dashboard.js اطلاعات را دریافت می کنیم. برای دریافت اطلاعات از هوک useLocation استفاده می کنیم.خب خسته نباشید حالا اطلاعات را به راحتی از دو روش بین کامپوننت ها منتقل نمودیم.فقط تنها نکته ای که باقی مونده Home.js است که برای زیبایی در اون یک لینک قرار می دهیم که به بخش درس ها بیاید.خب خسته نباشید به شما!مفاهیم اصلی React Router v6 رو در این نوشته با هم مرور کردیم. برای دسترسی به فایل های کامل پروژه به این آدرس رجوع کنید.</description>
                <category>فرشید کریمی</category>
                <author>فرشید کریمی</author>
                <pubDate>Mon, 07 Mar 2022 18:11:14 +0330</pubDate>
            </item>
                    <item>
                <title>ساخت فروشگاه ساده با React Redux - بخش اول</title>
                <link>https://virgool.io/@m_21642669/%D8%B3%D8%A7%D8%AE%D8%AA-%D9%81%D8%B1%D9%88%D8%B4%DA%AF%D8%A7%D9%87-%D8%B3%D8%A7%D8%AF%D9%87-%D8%A8%D8%A7-react-redux-%D8%A8%D8%AE%D8%B4-%D8%A7%D9%88%D9%84-ziknbu7speyt</link>
                <description>تمرین کار با React Redux با یک پروژه فروشگاهی جذاب :) اول از همه بگم که اگر با Redux آشنا نیستید، می تونید یه سر به این آموزش بزنید!در این پروژه با مفاهیم زیر کار می کنیم.React RouteReact ReduxAxiosReact HooksBootstrap 5در این پروژه جذاب یک فروشگاه به کمک Redux می سازیم که از API برای گرفتن اطلاعاتش کمک می گیره. خب اول از همه یک پروژه می سازیم و پکیج های مدنظر خودمون رو توش نصب می کنیم، من برای ساخت UI از Bootstrap5 و sass استفاده می کنم که برای شما می تونه فرق کنه بسته به اینکه با چی UI می زنید.npx create-react-app react-redux-ecommerce
cd react-redux-ecommerce
npm install axios react-router-dom redux react-redux bootstrap sassحالا یکم پروژه مون رو خلوت می کنیم و کد های زیر رو حذف می کنیم.(اینو بگم که من از ویرایشگر Atom تحت Lubuntu استفاده می کنم که البته برای شما می تونه هر چیز دیگری باشه)حذف کنید این 5 فایل روحالا فایل index.js مون رو هم خلوت می کنیم تا بدین شکل بشه (در انتهای بخش دوم سورس کد پروژه موجود است)فایل App.js مون هم بدین شکل مختصرش می کنیمخب برو بریم!یکی از مهم ترین کارها برای شکیل تر شدن کدتون در React ساختاربندی مناسب پروژه هست. بدین منظور داخل پوشه src یک پوشه به نام components درست می کنیم و یه پوشه به نام redux که داخل پوشه redux سه فولدر actions و constants و reducers رو می سازیم و یک فایل store.js می سازیم.یک فایل به نام action-types.js در فولدر constants ایجاد می کنیم و ثابت های زیر را قرار می دهیم. (نگران نباشید! جلوتر که بریم براتون واضحتر میشه مطالب)خب حالا یک فایل به نام productsActions.js داخل فولدر actions ایجاد می کنیم. اگر بخوام یه یادآوری از Redux کنم، باید بگم که action به ما در آپدیت state ها کمک می کرد که type نوع تغییر و payload ورودی فرآیند تغییر است! (واضح تر میشه بریم جلوتر!)خب حالا نوبت به Reducer میرسه که وظیفه انتقال state ها به store رو داره، بنابراین داخل فولدر reducers یه کد به اسم productsReducer.js ایجاد می کنیم. فعلا یه initialState الکی می گذاریم و بعدا با API جایگزینش می کنیم.حال یک فایل index.js درون پوشه reducers ایجاد می کنیم که تمامی reducer هامون رو تجمیع کنیم. البته ما در این پروژه فقط یک reducer داریم ولی به طور کلی برای ساختاربندی صحیح پروژه پیشنهاد می شود از متد combineReducers استفاده کنید.حالا کد store.js مون رو بدین شکل ویرایش می کنیم. یک store می سازیم که  reducers اون رو در index ساختیم و  از یک افزونه redux برای مرورگرها کمک می گیریم که در ادامه بهمون کمک می کنه.خب حالا برای اینکه کل App مون به store دسترسی داشته باشه از Provider استفاده می کنیم. کد index.js مون به شکل زیر می شود.خب حالا اگر localhost رو اجرا کنید و اکستنشن redux رو که گفتم برای مرورگرتون نصب کنید. می تونید state های برنامه رو ببینید.تا حالا کلی چیز میز آماده کردیم، نوبت اینه که بریم Component هامون رو ایجاد کنیم و چیزهایی هم ببینیم!چهار تا Component رو توی پوشه components ایجاد می کنیم و به مرور با محتوای خودمون پرشون می کنیم. اسم این کامپوننت ها Header.js و ProductListing.js و ProductDetails.js و ProductComponent.js هستش.هر چهار کامپوننت فعلا یکسان هستندحالا فایل App.js رو به عنوان محل تجمیع کامپوننت ها به صورت زیر ویرایش می کنیم. توجه به این نکته لازم است که ما از React Route استفاده می کنیم. همچنین فایل App.css هم به App.scss تغییر نام دادم.حالا فایل ProductListing.js رو به شکل زیر ویرایش کرده و کامپوننت ProductComponent رو در اون قرار میدهیم.حالا در ProductComponent.js ما توسط useSelector از فروشگاه state ها رو می گیریم و بعد بوسیله bootstrap یک card می سازیم تا موقتا تنها product ما را نشان دهد.خب در جلسه بعدی product هامون رو از یک API دریافت می کنیم و برناممون رو می سازیم.پس فعلا!</description>
                <category>فرشید کریمی</category>
                <author>فرشید کریمی</author>
                <pubDate>Tue, 01 Mar 2022 18:03:13 +0330</pubDate>
            </item>
                    <item>
                <title>ساخت فروشگاه ساده با React Redux - بخش دوم</title>
                <link>https://virgool.io/@m_21642669/%D8%B3%D8%A7%D8%AE%D8%AA-%D9%81%D8%B1%D9%88%D8%B4%DA%AF%D8%A7%D9%87-%D8%B3%D8%A7%D8%AF%D9%87-%D8%A8%D8%A7-react-redux-%D8%A8%D8%AE%D8%B4-%D8%AF%D9%88%D9%85-zesd20k37pry</link>
                <description>تمرین کار با React Redux با یک پروژه فروشگاهی جذاب :)خب ما از https://fakestoreapi.com به عنوان یک API برای تولید اطلاعات الکی استفاده می کنیم!در کد ProductListing که ProductComponent هامون رو توش نشون می دیم. این اطلاعات را از API دریافت می کنیم.(به صورت پیشفرض 20 محصول می باشد) دریافت اطلاعات در یک روند async با axios صورت می پذیرد و بعد از دریافت صحیح توسط dispatch می تونیم State رو تغییر بدهیم. همچنین به وسیله useEffect نیز مشخص می کنیم که دریافت اطلاعات فقط در رندر اولیه صورت پذیرد.همچنین Reducer مون رو هم به صورت زیر آپدیت می کنیم.کامپوننت ProductComponent.js رو به شکل زیر آپدیت می کنیم. همانطور که عرض کردم برای نوشتن UI از Bootstrap استفاده شده است.صرفا برای زیباتر شدن کد Header.js رو هم بدین شکل بهترش کردم.کد App.scss من هم بدین شکل است:خروجی کدمون تا بدین جاخب رفقا خسته نباشید، قولنج انگشتانتون رو بشکنید تا بریم ادامه ماجراجویی!حالا می خواهیم بعد از اینکه روی هر محصول کلید کردیم به صفحه خرید یا جزئیات اون محصول بریم. در وهله اول باید روی هر محصول که کلید می کنیم به route مدنظر رود، برای اینکار باید از Link در ProductComponent استفاده کنیم.خطوط افزوده شده پر رنگ تر هستندتا الان ما یک Reducer داشتیم و یک action که وظیفه تعیین product ها را داشتند. حال می خواهیم بفهمیم روی چه product ای کلید شده، ما با Redux اینکار رو انجام می دهیم.  بدین منظور یک Reducer جدید به فایل productsReducer.js مون اضافه می کنیم.همچنین به فایل index.js مونحالا صفحه ProductDetail رو می سازیم. خب اول با useParams که مربوط به مبحث router ها می باشد، مقدار productId رو می گیریم. بعد اطلاعات گرفته شده از API رو که مربوط به جزئیات محصول می باشد، dispatch کرده و state رو تغییر می دهیم.همچنین از useEffect استفاده می کنیم تا در صورتی که productId آپدیت شده و موجود می باشد fetch و متعاقبا dispatch صورت پذیرد.ساخت UI نیز نکته خاصی نداره، فقط ابتداش بررسی کردیم که product اگر موجود نیست Loading رو نشون بده.خسته نباشید پروژه مون تموم شد!راستی یه باگ کوچولو پروژه ما داره، اونم اینه که وقتی روی  یک محصول کلید می کنی و بعد برمیگردی به صفحه اولیه و یک محصول جدید رو انتخاب می کنی، محصول قبلی برای چند ثانیه نشون داده میشه. این به این علته که محصول قبلی هنوز توی store هستش و باید پاکش کنیم.اول یک action جدید به productsActions.js می افزاییمبعد فایل productsReducer.js رو متعاقبا آپدیت می کنیم.نهایتا تغییرات زیر را نیز در ProductDetails.js انجام می دهیمخب درست شد!همچنین با افزونه ای که در بخش قبل معرفی کردیم می تونید از صحت ترتیب action ها و عملکرد redux مطمئن شویدخب دوستان خسته نباشید، مسیر یکم طولانی بود ولی انجامش دادیم!فایل کامل پروژه در این آدرس قرار داده شده است. اگر اشکال یا سوال یا ایرادی در ارتباط با پروژه بود بهم بگید حتما!</description>
                <category>فرشید کریمی</category>
                <author>فرشید کریمی</author>
                <pubDate>Tue, 01 Mar 2022 18:02:40 +0330</pubDate>
            </item>
                    <item>
                <title>مدیریت State ها در React با Redux</title>
                <link>https://virgool.io/Solidity/react-redux-xnzaiihvdkie</link>
                <description>آموزش قدم به قدم مدیریت State ها با Redux  + استفاده از توابع Async در Reduxپیش نیاز:دانش اولیه درباره جاوااسکریپت و React.jsاگر کمی با React کار کرده باشید، بعد از مدتی متوجه میشید که مدیریت State ها در React مسئله بسیار مهمی است. رد و بدل کردن State ها بین Component ها، re-render شدن های اضافی که آپدیت کردن Stateها به سایت شما اضافه می کنه و غیره.اما با Redux شما می تونید تا حدود زیادی دردسرهای کار با State ها در react رو کم کنید. توی Redux:همه State ها در یک جای به نام store جمع میشننیازی به رد و بدل کردن مکرر State ها نداریمخود Redux به صورت efficient ای Component ها رو آپدیت می کنه و اما Redux چیست؟خیلی مختصر بخوام بگم Redux یک ابزار مدیریت State ها برای React است و بعد از اینکه یه مدت باهاش کار کنید، قدرشو می دونید :)در ادامه در یک پروژه مختصر قدم با قدم با Redux آشنا خواهیم شد. پیش فرض من اینه که شما با ایجاد پروژه React و خودش آشنایی دارید . آماده سازی پروژهبا دستور زیر یک پروژه ایجاد می کنیمnpx create-react-app react-redux-tutorialخب بعدش پروژه تون رو خلوت کنید، پیشفرض من اینه که App.js تون رو این شکلی کردید.const App= () =&gt; {
return( 
&lt;div&gt;
&lt;h1&gt;Hello World&lt;/h1&gt;
&lt;/div&gt;
)}
export default  App;افزودن storeبا دستور زیر نصب اولیه redux و  react-redux رو انجام بدیدnpm install redux &amp;&amp; npm install react-redux حالا نوبت ایجاد store است که محل مدیریت State هاست.import {createStore} from &#039;redux&#039;
const store =createStore();
const App= () =&gt; {
return (
      &lt;div&gt;
        &lt;h1&gt;Hello  World&lt;/h1&gt;
      &lt;/div&gt; 
  )
}
export default  Appافزودن Reducerخب گفتیم store محل مدیریت State هاست، خب پس کی بهش State های برنامه رو برسونه؟اینجا نوبت به جناب Reducer می رسه که تابعی است که State های برنامه رو تقدیم store می کنه. همچنین فعلا یه متغیر هم درست می کنیم که مثلا state برنامه ماست، اسم متغیر هم می گذاریم initialState.import {createStore} from &#039;redux&#039;

const initialState = {username : &amp;quotFarshid&amp;quot};
const returnStateReducer = (state= initialState) =&gt;{
    return state;
  }
const store =createStore(returnStateReducer);
const App= () =&gt; {
  return (
      &lt;div&gt;
      &lt;h1&gt;Hello  World&lt;/h1&gt;
      &lt;/div&gt;
    )
}
export default  App;همچنین Store را به وسیله Provider به کل برنامه محاط می کنیم.import {createStore} from &#039;redux&#039;
import {Provider} from &#039;react-redux&#039;

const initialState = {username : &amp;quotFarshid&amp;quot};
const returnStateReducer = (state= initialState) =&gt;{
    return state;
}
const store =createStore(returnStateReducer);
const App= () =&gt; {
  return (
    &lt;Provider store={store}&gt;
      &lt;div&gt;
        &lt;Header/&gt;
        &lt;h1&gt;Hello  World&lt;/h1&gt;
      &lt;/div&gt;
    &lt;/Provider&gt;
  )
}
export default  App;خب حالا کل برنامه به State های درون Store دسترسی داره و نیازی به رد و بدل کردن prop ها نیست. حالا برای کامل تر شدن مثال ما یک Component به نام Header اضافه می کنیم.const Header = ()=&gt; {
  return (
    &lt;div&gt; Header &lt;/div&gt;
  )}
export default Headerکد App.js مون هم این شکلی میشه الانimport {createStore} from &#039;redux&#039;
import {Provider} from &#039;react-redux&#039;
import Header from &#039;./Header&#039;

const initialState = {username : &amp;quotFarshid&amp;quot};
const returnStateReducer = (state= initialState) =&gt;{
    return state;
}
const store =createStore(returnStateReducer);
const App= () =&gt; {
  return (
    &lt;Provider store={store}&gt;
      &lt;div&gt;
        &lt;Header/&gt;
        &lt;h1&gt;Hello  World&lt;/h1&gt;
      &lt;/div&gt;
    &lt;/Provider&gt;
  )}
export default  App;بزن بریم ...خب حالا همانطور که حدس زدید، میریم که از Header به username دسترسی پیدا کنیم. تابعی که react-redux برای دسترسی به State ها به ما معرفی می کنه، اسمش useSelector هست. به عبارت دیگر بوسیله این تابع می تونیم به Store برنامه مون یه سری بزنیم و State مدنظرمون رو از فروشگاه انتخاب کنیم!const Header = ()=&gt; {
  const user = useSelector((state) =&gt; state.username);
  return (
    &lt;div&gt;{user} &lt;/div&gt;
  )
}
export default Headerخب حالا همچین چیزی داریمگفتیم که Reducer جایی است که State های ما رو تحویل store می ده، جالبه بدونید که جناب Reducer علاوه بر وظیفه ای که گفتم، می تونه State رو آپدیت هم کنه و بعد تحویل Store بده. برای آپدیت State تابع Reducer ورودی به نام action در نظر گرفته است.import { createStore } from &amp;quotredux&amp;quot
import { Provider } from &amp;quotreact-redux&amp;quot
import Header from &amp;quot./Header&amp;quot

const initialState = { username: &amp;quotFarshid&amp;quot };
const returnStateReducer = (state = initialState, action) =&gt; { 
if (action.type === &amp;quotupdateUser&amp;quot) {
 return { ...state, username: &amp;quotFarhad&amp;quot }; 
} else {
  return state;
 }
};
const store = createStore(returnStateReducer);
const App = () =&gt; {
 return (
&lt;Provider store={store}&gt;
 &lt;div&gt;
   &lt;Header /&gt;
    &lt;h1&gt;Hello World&lt;/h1&gt;
 &lt;/div&gt;
  &lt;/Provider&gt;
);
};
export default App;برای اینکه بفهمیم چه تغییر دلخواهی قراره روی State با action بدیم یک type برای action مون تعیین می کنیم. در کد بالا در صورتی که action.type برابر updateUser باشد، سایر State ها غیر username دست نخورده تحویل داده می شوند (با ...) و username به فرهاد تغییر می کند.استفاده از action برای آپدیت Stateحالا میریم توی Header.js و یک button می گذاریم که به وسیله اون بتونیم action گفته شده در بالا(updateUser) را فراخوانی کنیم. تابعی که می تواند State ما رو آپدیت کنه و تحویل Reducer مون بده یه hook به نام useDispatch است.import {useDispatch, useSelector} from &#039;react-redux&#039;

const Header = ()=&gt; {
  const user = useSelector((state) =&gt; state.username);
  const dispatch = useDispatch();
  return (
    &lt;div&gt;{user}
    &lt;button ={()=&gt; dispatch({type: &amp;quotupdateUser&amp;quot})}&gt;Change User&lt;/button&gt;
    &lt;/div&gt;
  )
}
export default Headerخب حالا اگر روی دکمه کلید کنید اسم Farshid به Farhad تغییر می کند.تبریک به من، تبریک به تو، تبریک به همه! موفق شدیم که State مون رو با Redux آپدیت کنیم. اینکار خیلی راحتتر میشه براتون وقتی چند بار تمرین کنه، فقط کافیه مفاهیم Store و Reducer و Dispatch رو خیلی ساده برای خودتون مرور کنید.آپدیت State با ورودی کاربرحالا می خواهیم با ورودی که از کاربر می گیریم username رو آپدیت کنیم. برای اینکار کافیه بدونیم که action علاوه بر type یه ویژگی به payload داره که می تونیم محتوایی که قراره جایگزین بشه رو هم به Reducer بده. خب حالا ما یک type جدید اولا اضافه می کنیم که برای آپدیت State با ورودی کاربره و از اونور هم payload رو از input گرفته و dispatch می کنیم.import {useDispatch, useSelector} from &#039;react-redux&#039;

const Header = ()=&gt; {
  const user = useSelector((state) =&gt; state.username);
  const dispatch = useDispatch();
return (
    &lt;div&gt;{user}
    &lt;input ={(e)=&gt; dispatch({type: &amp;quotupdateMyName&amp;quot, payload: e.target.value}) }&gt;
    &lt;/input&gt;
    &lt;button ={()=&gt; dispatch({type: &amp;quotupdateUser&amp;quot})}&gt;Change User&lt;/button&gt;
    &lt;/div&gt;
  )}
export default Headerimport {createStore} from &#039;redux&#039;
import {Provider} from &#039;react-redux&#039;
import Header from &#039;./Header&#039;

const initialState = {username : &amp;quotFarshid&amp;quot};
const returnStateReducer = (state= initialState, action) =&gt;{
  if(action.type === &amp;quotupdateUser&amp;quot){
    return {...state, username : &amp;quotFarhad&amp;quot};
  }else if(action.type === &amp;quotupdateMyName&amp;quot){
    return {...state, username : action.payload};
  }else {
    return state;
  }}
const store =createStore(returnStateReducer);
const App= () =&gt; {
  return (
    &lt;Provider store={store}&gt;
      &lt;div&gt;
        &lt;Header/&gt;
        &lt;h1&gt;Hello  World&lt;/h1&gt;
      &lt;/div&gt;
    &lt;/Provider&gt;
  )}
export default  App;حالا اسممون رو می تونیم آپدیت کنیم.توابع Async در Reduxحالا فرض کنیم شما می خواهید یک سری دیتا از یک API گرفته و بعد State خودتون رو آپدیت کنید. از اونجا که این یک فرآیند Async است و Redux اساسا طوری ساخته شده که Sync کار کنه، نیاز به یک واسط داریم تا توانایی Async رو به Redux اضافه کنه که اسمش Redux-thunk می باشه!برای استفاده ازش ابتدا با دستور npm i redux-thunk نصبش می کنیم. حالا برای اینکه به store مون بگیم قراره به صورت Async با State هاش کار بشه از متد applyMiddleware در redux استفاده می کنیم، به شکل زیر:import {createStore, applyMiddleware} from &#039;redux&#039;
import {Provider} from &#039;react-redux&#039;
import thunk from &#039;redux-thunk&#039;
import Header from &#039;./Header&#039;

const initialState = {username : &amp;quotFarshid&amp;quot};
const returnStateReducer = (state= initialState, action) =&gt;{
  if(action.type === &amp;quotupdateUser&amp;quot){
    return {...state, username : &amp;quotFarhad&amp;quot};
  }else if(action.type === &amp;quotupdateMyName&amp;quot){
    return {...state, username : action.payload};
  }else {
    return state;
  }}
const store =createStore(returnStateReducer, applyMiddleware(thunk));
const App= () =&gt; {
  return (
    &lt;Provider store={store}&gt;
      &lt;div&gt;
        &lt;Header/&gt;
        &lt;h1&gt;Hello  World&lt;/h1&gt;
      &lt;/div&gt;
    &lt;/Provider&gt;
  )}
export default  App;برای گرفتن کاربر از API، ما از API رایگان https://randomuser.me/ استفاده می کنیم که به راحتی میشه ازش اطلاعات کاربری fake گرفت و در کارهای توسعه استفاده کرد.حالا بیایین یکم مسئله رو ساده کنیم!فرض کنید ما به store مون (فروشگاهمون!) می خواهیم یه سری اطلاعات رو از یه راه دور بدیم، اینجا سه تا فاز داریم که معادل سه State می شوندگرفتن اطلاعات یا Loadingاطلاعات به درستی دریافت شدندبا خطا مواجه شدیمخب حالا کدش اینجوری میشه:import {createStore, applyMiddleware} from &#039;redux&#039;
import {Provider} from &#039;react-redux&#039;
import thunk from &#039;redux-thunk&#039;
import Header from &#039;./Header&#039;

const initialState = {username : &amp;quotFarshid&amp;quot};
const returnStateReducer = (state= initialState, action) =&gt;{
  if(action.type === &amp;quotupdateUser&amp;quot){
    return {...state, username : &amp;quotFarhad&amp;quot};
  }else if(action.type === &amp;quotupdateMyName&amp;quot){
    return {...state, username : action.payload};
  }else if(action.type === &amp;quotloadingUser&amp;quot){
    return {...state, username : &amp;quotLoading...&amp;quot};
  }else if(action.type === &amp;quotasyncUser&amp;quot){
    return {...state, username : action.payload};
  }else if(action.type === &amp;quoterror&amp;quot){
    return {...state, username : &amp;quoterror&amp;quot};
  }else {
    return state;  
}
}

const store =createStore(returnStateReducer, applyMiddleware(thunk));
const App= () =&gt; {
  return (
    &lt;Provider store={store}&gt;
      &lt;div&gt;
        &lt;Header/&gt;
        &lt;h1&gt;Hello  World&lt;/h1&gt;
      &lt;/div&gt;
    &lt;/Provider&gt;
  )}
export default  App;حالا بریم سمت Header.js یعنی جایی که قراره اطلاعات از API گرفته بشه و فرستاده بشه برای Store ما. اولا یک دکمه اضافه می کنیم که تریگر ما برای گرفتن دیتا از API باشد. همانطور که قبلا گفتیم dispatch خبرچینی است که تغییر State رو به گوش Store می رسونه :)حال ما نیاز داریم تا تابعی بسازیم که براساس وضعیت اخذ داده از API برای ما dispatch تولید کنه یا به عبارتی خبر ببره. این کار رو با تابع asyncRandomUser انجام می دیم. با کلید کاربر روی دکمه مربوطه هم خود این تابع رو dispatch می کنیم تا به گوش store برسه.import {useDispatch, useSelector} from &#039;react-redux&#039;

const asyncRandomUser= () =&gt;{
        return async function (dispatch){
          dispatch({type:&amp;quotloadingUser&amp;quot});
          try{
              const request = await fetch(&amp;quothttps://randomuser.me/api&amp;quot)
              const userData = await request.json();
              console.log(&amp;quotGot user&amp;quot, userData);
              dispatch({type:&amp;quotasyncUser&amp;quot, payload: userData.results[0].name.first})
          }catch(error){
            dispatch({type:&amp;quoterror&amp;quot})
          }
        }
}

const Header = ()=&gt; {
  const user = useSelector((state) =&gt; state.username);
  const dispatch = useDispatch();
  return (
    &lt;div&gt;{user}
    &lt;input ={(e)=&gt; dispatch({type: &amp;quotupdateMyName&amp;quot, payload: e.target.value}) }&gt;
    &lt;/input&gt;
    &lt;button ={()=&gt; dispatch({type: &amp;quotupdateUser&amp;quot})}&gt;Change User&lt;/button&gt;
    &lt;button ={()=&gt; dispatch(asyncRandomUser())}&gt;Fetch User&lt;/button&gt;
    &lt;/div&gt;
  )}
export default Headerپایان! خسته نباشید به همگی، ما تونستیم هم به صورت سنکرون و هم آسنکرون State ها رو با Redux مدیریت کنیم. به همین راحتی!از توجه تون متشکرم!ممنون میشم اگر ایراد فنی یا تایپی وجود داشت بهم اطلاع بدید تا اصلاحش کنم. امیدوارم براتون مفید بوده باشه :)</description>
                <category>فرشید کریمی</category>
                <author>فرشید کریمی</author>
                <pubDate>Sat, 26 Feb 2022 20:26:28 +0330</pubDate>
            </item>
            </channel>
</rss>