منابع آموزشی و پژوهشی، برای دانشگاه و مدرسه
راهنمای انتخابمیز نویسنده
آموزش javascriptدرس ۱ از ۱رایگان

مدیریت وضعیت در JavaScript؛ طراحی reducer بدون تغییر دادهٔ قبلی

در اولین درس دورهٔ دوم جاوااسکریپت، وضعیت یک کتابخانه را با reducer خالص مدل می‌کنیم؛ بدون دست‌کاری دادهٔ قبلی، با اعتبارسنجی ورودی و تمرین پاسخ‌دار.

فضای تمرینبه‌روزرسانی: ۱۴۰۵/۸/۵
معماری و داده

این آموزش، درس اول دورهٔ دوم جاوااسکریپت و ادامهٔ مسیر «از پایه تا پروژه» است. پیش‌نیاز آن تسلط به تابع، آرایه، شیء و Promise است. در این دوره به‌جای حفظ دستورهای بیشتر، روی قابل‌پیش‌بینی‌بودن رفتار برنامه کار می‌کنیم: وضعیت، جست‌وجو، پاسخ‌های ناهم‌زمان، صف کار، کش، ذخیره‌سازی، رابط کاربری و آزمون. مثال‌ها مستقل‌اند و در پایان می‌توان آن‌ها را به یک کتابخانهٔ آموزشی کوچک وصل کرد.

فرض کنید کاربر یک درس را نشان می‌کند و بعد فیلتر جست‌وجو را تغییر می‌دهد. اگر چند تابع، یک شیء مشترک را بی‌قاعده تغییر دهند، پیدا کردن علت تغییر رابط دشوار می‌شود. راه ساده‌تر این است که هر اتفاق را به یک پیام، یا action، تبدیل کنیم. تابع reducer وضعیت قبلی و پیام را می‌گیرد و وضعیت بعدی را برمی‌گرداند. این الگو به کتابخانهٔ خاصی وابسته نیست. در مثال ما، ذخیره‌سازی و کار با صفحه بیرون از reducer می‌مانند؛ به همین دلیل می‌توان رفتار آن را بدون مرورگر آزمایش کرد.

نمونهٔ اجرایی

javascript
function reducer(state, action) {
  switch (action.type) {
    case "query":
      if (typeof action.value !== "string") return state;
      return { ...state, query: action.value };
    case "bookmark": {
      const id = action.id;
      if (typeof id !== "string" || !id.trim()) return state;
      const ids = state.saved.includes(id)
        ? state.saved.filter(value => value !== id)
        : [...state.saved, id];
      return { ...state, saved: ids };
    }
    default: return state;
  }
}
const before = { query: "", saved: [] };
const after = reducer(before, { type: "bookmark", id: "js-1" });
console.log(before.saved.length, after.saved.length); // 0 1
console.log(reducer(after, { type: "bookmark", id: "js-1" }).saved.length); // 0

در حالت bookmark، هم شیء بیرونی و هم آرایهٔ saved تازه ساخته می‌شوند. فقط نوشتن {...state} و سپس اجرای push روی state.saved کافی نیست؛ آن کپی سطحی هنوز به آرایهٔ قبلی اشاره می‌کند. در مقابل، شاخهٔ query نیازی به کپی آرایهٔ saved ندارد، چون آن را تغییر نمی‌دهد. هدف، کپی‌کردن بی‌دلیل همهٔ داده‌ها نیست؛ فقط مسیر تغییر باید تازه ساخته شود.

خالص‌بودن تابع یعنی برای ورودی یکسان، خروجی قابل‌پیش‌بینی داشته باشیم و اثر جانبی بیرونی ایجاد نکنیم. بنابراین زمان جاری، درخواست شبکه و localStorage را در این تابع قرار نمی‌دهیم. اگر ثبت زمان لازم باشد، آن را هنگام ساخت action تولید و به reducer ارسال می‌کنیم. قرارداد این مثال می‌گوید state.saved همیشه آرایه‌ای از شناسه‌های معتبر است؛ دادهٔ ورودی خارجی باید قبل از رسیدن به این لایه اعتبارسنجی شود.

اجرای نمونه در کنسول مرورگر، Node.js یا فضای کنسولی درس‌آوند ممکن است. خروجی نخست نشان می‌دهد وضعیت اولیه تغییر نکرده و خروجی دوم نشان می‌دهد نشان‌کردن دوباره، درس را از فهرست برمی‌دارد.

تمرین و پاسخ تشریحی

تمرین: بدون تغییر reducer، بررسی کنید دو بار فرستادن پیام bookmark وضعیت نشان‌ها را به حالت اولیه برمی‌گرداند. سپس پیام ناشناخته‌ای بفرستید و بررسی کنید همان مرجع قبلی بازگردد. چرا برابری ظاهری JSON، آزمون مناسبی برای ثابت‌ماندن مرجع نیست؟

javascript
const start = { query: "", saved: [] };
const once = reducer(start, { type: "bookmark", id: "x" });
const twice = reducer(once, { type: "bookmark", id: "x" });
if (start.saved.length !== 0 || twice.saved.length !== 0) throw Error("mutation");
if (reducer(start, { type: "unknown" }) !== start) throw Error("identity");
console.log("state checks passed");

پاسخ تشریحی: عملگر !== هویت شیء را می‌سنجد، ولی JSON فقط نمایش داده را مقایسه می‌کند. دو شیء مستقل می‌توانند JSON یکسان داشته باشند. در پروژهٔ نهایی، reducer مرجع قواعد تغییر وضعیت است و نمایش صفحه مسئولیتی جدا دارد.
منبع فنی برای مرور اشیا و ارجاع‌ها: MDN، Working with objects. طراحی مثال و تمرین این درس تألیف آموزشی درس‌آوند است.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_objects

پیش‌نیاز و محیط اجرای مثال‌ها

سطح متوسط؛ پیش‌نیاز: دورهٔ مقدماتی JavaScript درس‌آوند. مثال‌های این درس در Node.js 24، کنسول مرورگر یا فضای اجرای کنسولی سایت قابل اجرا هستند. تمرین را ابتدا بدون دیدن پاسخ حل کنید.

پیشرفت روی همین مرورگر ذخیره می‌شود.

یکجا انتخاب کن، راحت‌تر دریافت کن

انتخاب‌های من ۰ منبع

مجموعهٔ مطالعه‌ات را بساز.

کنار مقاله‌ها «انتخاب» را بزنید تا چند فایل را با هم دریافت کنید.

انتخاب مقاله‌های رایگان