مدیریت State در فرانتاند از انتخاب Redux یا Context شروع نمیشود. ابتدا باید بدانید هر داده متعلق به کجاست، چه کسی آن را تغییر میدهد، تا چه زمانی معتبر است و در تعارض میان Browser، Server، Tab دیگر یا پاسخ دیررس کدام نسخه برنده است. اگر این قرارداد روشن نباشد، هر Store فقط آشفتگی را در یک مکان متمرکز میکند.
یک Filter قابل اشتراک بهتر است در URL باشد؛ وضعیت بازبودن Modal محلی است؛ Product list نسخه Cacheشده از حقیقت Server است؛ Draft شاید نیاز به Persistence داشته باشد؛ Checkout یک Workflow با Transitionهای محدود است. این راهنما State را طبقهبندی میکند، مدل سازگاری میسازد و بعد ابزار مناسب React، Vue یا معماری دیگر را انتخاب میکند.
| داده | مالک محتمل | انتخاب اولیه | خطای رایج |
|---|---|---|---|
| بازبودن Dropdown | Component | Local state | قرار دادن در Store سراسری |
| Filter و Page نتایج | Navigation/URL | Query parameter | از دسترفتن Back/Share/Refresh |
| فهرست سفارشها | Server | Query cache | Copy در Global store و Cache دوگانه |
| سبد خرید | بسته به محصول؛ Server یا Client+sync | Domain contract | اعتماد به Total سمت Client |
| مرحله پرداخت | Workflow/Server | State machine + persisted order state | چند Boolean متناقض |
State چیست و چه چیزی State نیست؟
State حداقل اطلاعاتی است که برای توصیف وضعیت فعلی سیستم و تعیین رفتار بعدی لازم است. هر مقدار محاسبهشده لزوماً State نیست. اگر fullName از firstName و lastName قابل محاسبه است، ذخیره هر سه، احتمال ناسازگاری میسازد.
راهنمای رسمی React برای ساختار State بر گروهبندی دادههای مرتبط و حذف State متناقض، تکراری، زائد و بیشازحد تودرتو تأکید میکند. این اصول به React محدود نیستند.
| مفهوم | تعریف | مثال |
|---|---|---|
| Source state | اطلاعات حداقلی مستقل | selectedId |
| Derived value | از Source در Render/Selector محاسبه میشود | Selected product |
| Event | چیزی که رخ داده | checkout/submitted |
| Effect | تعامل با سیستم بیرونی | Request، Storage، Analytics |
| Cache | نسخه قابلحذف و بازسازی از Source دیگر | Query result |
مرز این مفاهیم از نام کتابخانه مهمتر است. وقتی Effect داخل Reducer، Cache بهعنوان Truth یا Derived value بهعنوان Source ذخیره شود، Debug دشوار میشود.
یک Source of Truth برای هر State، نه یک Store برای همه
«Single source of truth» یعنی برای هر قطعه State یک Owner روشن وجود دارد؛ نه اینکه تمام State برنامه باید داخل یک Object سراسری باشد. React نیز State مشترک را به نزدیکترین والد مشترک Lift میکند و تصریح میکند Stateهای مختلف میتوانند در مکانهای مختلف زندگی کنند.
State را تا جای ممکن نزدیک مصرفکننده نگه دارید. بالا بردن Scope هزینه Subscription، Coupling، تست و احتمال تغییر ناخواسته را زیاد میکند. تنها وقتی چند شاخه واقعاً هماهنگی میخواهند، Owner را بالا ببرید.
هشت نوع State در اپلیکیشن وب
| نوع | نمونه | Lifetime | ابزار اولیه |
|---|---|---|---|
| Ephemeral UI | Modal، hover، accordion | Component/session کوتاه | Local state |
| URL/navigation | Filter، search، tab، page | History/share/refresh | Router و URL |
| Form/draft | Field، touched، error، step | تا submit یا resume | Form/local reducer |
| Server state | Product، order، profile | Cache با freshness | Query/cache layer |
| Client domain | Builder canvas، انتخاب پیچیده | Session/feature | Reducer/store/state machine |
| Session/auth projection | User، capability، expiry | Session | Server session + client projection |
| Persisted/offline | Draft، outbox، preference | بین reload/device محدود | Storage/IndexedDB + migration |
| External environment | Online status، media query، browser API | خارج React/Vue | External-store adapter |
یک ویژگی میتواند چند نوع داشته باشد. Search page ممکن است Query در URL، نتایج در Server cache، focus محلی و Recent searches در Persistence داشته باشد. آنها را یک Object «searchState» نکنید مگر Update و Lifetime مشترک داشته باشند.
State contract؛ قبل از انتخاب ابزار
| فیلد | پرسش | مثال |
|---|---|---|
| Identity | این State دقیقاً چه چیزی را توصیف میکند؟ | Order ID و Version |
| Owner | Browser، Server، URL یا Worker؟ | Server مالک Payment status |
| Scope | Component، Route، Tab، User یا Device؟ | Filter در Route |
| Lifetime | Render، Session، Reload یا Offline؟ | Draft هفت روز |
| Initial source | از کجا Boot میشود؟ | SSR payload یا API |
| Mutation | چه Event/Commandی تغییر میدهد؟ | Quantity changed |
| Consistency | Strong، eventual یا optimistic؟ | Stock نیاز به Server confirm |
| Freshness | چه زمانی Stale میشود؟ | Price پس از ۳۰ ثانیه/رویداد |
| Concurrency | پاسخ دیررس/دو Tab/دو Device؟ | Version conflict |
| Security | آیا Sensitive یا Authoritative است؟ | Access token در State ممنوع |
| Failure | Retry/Rollback/Recovery چیست؟ | Optimistic rollback |
| Evidence | چه Event/Metricی Debug میکند؟ | Mutation ID و cache invalidation |
اگر تیم درباره Owner یا Consistency جواب متفاوت میدهد، افزودن کتابخانه هنوز زود است.
نردبان تصمیم: سادهترین مکان معتبر را انتخاب کنید
- آیا قابل محاسبه است؟ State نسازید؛ Derived value/Selector بسازید.
- آیا Server/Framework آن را مالک است؟ دوباره در Client کپی نکنید.
- آیا باید Share/Bookmark/Back شود؟ URL.
- آیا فقط یک Component نیاز دارد؟ Local state.
- آیا چند Component نزدیک هماهنگاند؟ Lift state.
- آیا Transitionهای پیچیده در یک Feature دارید؟ Reducer/state machine.
- آیا Server data با Cache/freshness است؟ Query layer.
- آیا چند Feature دور، Subscription دقیق و DevTools میخواهند؟ External/global store.
Props drilling همیشه مشکل نیست؛ Prop صریح dependency را آشکار میکند. Context نیز «State manager» کامل نیست؛ کانال توزیع Value است و Scope/Update آن باید طراحی شود.
State محلی، Lift و Context در React
برای هماهنگی دو Component، ابتدا State را به نزدیکترین والد مشترک Lift کنید. اگر Tree عمیق شد، Reducer و Context در مستندات React منطق Transition و توزیع State/Dispatch را جدا میکنند.
| الگو | مناسب | هشدار |
|---|---|---|
| Local state | UI مستقل و موقت | Duplicate در sibling |
| Lift state | چند Component نزدیک | Owner بیشازحد بالا |
| Reducer | Transitionهای مرتبط و قابل تست | Effect داخل Reducer |
| Context | Value در Subtree | Provider بزرگ و update پر频 |
| External store | چند Feature/خارج React | Global dumping ground |
برای Store خارج React، useSyncExternalStore API رسمی Subscription به External store است و برای Server rendering نیز snapshot جدا میخواهد. Subscription دستی با Effect ممکن است در Concurrent rendering snapshot ناسازگار بدهد.
Server State با Global Client State یکی نیست
Server state Remote، Shared، Async و ممکن است بدون اطلاع Client تغییر کند. علاوه بر Value، Loading، Error، freshness، retry، cancellation، pagination، invalidation و garbage collection دارد. Copy پاسخ API در Store عمومی معمولاً شما را وادار میکند Cache را دوباره و ناقص بسازید.
| ویژگی | Client/UI State | Server State |
|---|---|---|
| Authority | Browser/feature | Server |
| Sync | همان Runtime | Network و async |
| Freshness | تا Event محلی | Stale/invalidate/refetch |
| Concurrency | محدود به UI | Clientها و Workerهای دیگر |
| Failure | Validation/logic | Timeout، retry، partial، offline |
| Lifecycle | Component/route | Cache/subscriber/GC |
در Redux، راهنمای رسمی Redux Redux Toolkit را ابزار پیشنهادی و RTK Query را مسیر پیشفرض Fetch/Cache در اپ Redux معرفی میکند. این Recommendation مخصوص اکوسیستم Redux است؛ به معنی نیاز همه پروژهها به Redux نیست.
Cache key، Freshness و Invalidation
Cache key هویت Data است. اگر Query function به status، page و market وابسته است، Key باید آنها را نمایندگی کند. مستندات TanStack Query نیز متغیرهای مؤثر بر Query را بخشی از Query key میداند.
| قرارداد Cache | سؤال | Failure |
|---|---|---|
| Key | Tenant/User/Locale/Filter/Version در Identity هستند؟ | نشت یا داده اشتباه |
| Freshness | چه مدت داده Fresh است؟ | Refetch زیاد یا اطلاعات کهنه |
| Invalidation | کدام Mutation/Event چه Keyهایی را stale میکند؟ | UI ناسازگار |
| Retention/GC | Cache بدون subscriber تا کی؟ | Memory growth |
| Retry | کدام خطا، چند بار و با چه Backoff؟ | Request storm |
| Cancellation | Response قدیمی چگونه بیاثر میشود؟ | Race و overwrite |
Important Defaults رسمی TanStack Query یادآوری میکند Queryها بهطور پیشفرض Stale در نظر گرفته میشوند و Retry/GC رفتارهای پیشفرض دارند. Default را Contract محصول فرض نکنید؛ برای Price، Profile و Static catalog نیازهای متفاوت تعریف کنید.
برای تفاوت Cache با Source of truth، Invalidation، Stale budget و Stampede، راهنمای معماری Cache در وب را ببینید.
Form State و Draft؛ یک Domain مستقل
Form فقط Map فیلدها نیست. Raw value، parsed value، touched/dirty، sync/async validation، submit status، server error، draft version و accessibility دارد. همه فرم را Global نکنید؛ Scope معمولاً Route/Feature است.
قرارداد Submit
- Client validation برای UX است؛ Server دوباره اعتبارسنجی میکند؛
- Double submit با disabled UI بهتنهایی حل نمیشود؛ Idempotency سمت Server لازم است؛
- Server error را به Field/Form/Global درست Map کنید؛
- Draft persistence باید Schema version و Migration داشته باشد؛
- بعد از Success، Reset فقط State متعلق به همان Form را پاک کند؛
- Navigation با Unsaved changes باید Recovery و Accessibility روشن داشته باشد.
URL State؛ State قابل اشتراک و قابل بازگشت
Search، Sort، Filter، Pagination، selected tab و گاهی Modal قابل لینک باید در URL قرار گیرند. مزیت: Refresh، Back/Forward، Bookmark، Share، Analytics و SSR قابل پیشبینیتر میشوند.
| قاعده | نمونه | هشدار |
|---|---|---|
| Canonical serialization | ترتیب و Default ثابت | URLهای معادل متعدد |
| Validation | Page عدد مثبت، sort از enum | اعتماد به Query خام |
| Replace vs push | Typing شاید replace؛ submit push | History پر از هر keystroke |
| Sensitive data | هرگز Token/PII در URL | Log، Referrer و Share |
| Unicode | UTF‑۸ و normalization | فارسی/نیمفاصله معادلهای متفاوت |
URL را هم State بیاعتماد ورودی بدانید: Parse، Validate و Default کنید. Server query را صرفاً با String کلاینت اجرا نکند.
Derived State، Selector و Effectهای غیرضروری
Derived data را هنگام Render یا با Selector محاسبه کنید. استفاده از Effect برای Sync کردن دو State داخلی، یک Render اضافی و Window ناسازگاری میسازد. مستندات React درباره Effectهای غیرضروری نیز محاسبه داده برای Render و Event handling را از Effect بیرونی جدا میکند.
Memoization فقط وقتی لازم است که محاسبه گران یا Reference stability برای Subscription/child مهم باشد. Memoize همه Selectorها میتواند Memory و پیچیدگی را زیاد کند. ابتدا Profile کنید.
ساختار State؛ Normalization و Impossible state
داده تکراری را با ID reference و Entity map مدیریت کنید، بهخصوص وقتی یک Entity در چند List دیده میشود. اما Response ساده و کوچک را بیدلیل شبیه Database نکنید.
چند Boolean میتوانند حالت ناممکن بسازند:
{ isIdle, isSubmitting, isPaid, hasError }بهجای ترکیبهای متناقض، State را به Union/State machine تبدیل کنید:
idle → submitting → awaiting_payment → paid
↘ failed → retryingTransition باید Event، Guard و Effect مشخص داشته باشد. برای Checkout، Onboarding، Upload و Approval، State machine اغلب از Store عمومی قابل توضیحتر است.
Optimistic Update؛ سرعت ادراکی با قرارداد Rollback
Optimistic update قبل از تأیید Server UI را تغییر میدهد. برای Like ساده مناسبتر از انتقال پول یا موجودی بحرانی است. چهار چیز لازم است: mutation identity، snapshot/patch، rollback/reconcile و نمایش وضعیت Pending.
| مرحله | کار | ریسک |
|---|---|---|
| Prepare | Validation و mutation ID | Duplicate |
| Optimistic apply | Patch محلی و Pending marker | UI ادعای قطعی |
| Server commit | Idempotency/version check | Conflict |
| Success | Reconcile با Response authoritative | Temporary ID mismatch |
| Failure | Rollback یا refetch و Error قابل اقدام | Silent divergence |
Rollback به «برگرداندن کل Cache» محدود نیست؛ ممکن است Mutation دیگر بعد از آن آمده باشد. Patch معکوس، Version و refetch هدفمند را متناسب با Concurrency طراحی کنید.
Race condition و پاسخ دیررس
کاربر «تهران» را جستوجو و بلافاصله «شیراز» را وارد میکند؛ پاسخ تهران دیرتر میرسد و Result جدید را overwrite میکند. راهحل میتواند Cancellation، request ID، sequence، query key جدا یا بررسی latest intent باشد.
| Race | کنترل |
|---|---|
| Out-of-order response | Abort/sequence/latest-intent guard |
| Double submit | Idempotency key و server dedupe |
| Stale closure | Updater/event design و dependency درست |
| Two-tab edit | Version/ETag، conflict UI و channel sync |
| Background refetch vs edit | Draft/source separation و merge policy |
Realtime State؛ Event ordering، Dedupe و Resync
WebSocket/SSE State را «خودکار Real-time» نمیکند. Connection ممکن است قطع، Event تکراری، جاافتاده یا خارج ترتیب باشد. Event contract شامل ID، entity ID، version/sequence، timestamp، type و payload schema لازم است.
- Snapshot اولیه بگیرید؛
- از Cursor/Version مشخص subscribe کنید؛
- Event را Dedupe و ترتیب را Validate کنید؛
- Gap را تشخیص و Resync کنید؛
- پس از reconnect، Subscription و State را Reconcile کنید.
اگر Event فقط «چیزی تغییر کرد» میگوید، Query مربوط را Invalidate کنید. اگر Patch کامل و Versioned است، Cache را دقیق Update کنید.
Persistence و localStorage؛ Convenience با ریسک
localStorage میان Sessionهای Browser باقی میماند و API آن Synchronous است؛ MDN رفتار آن را برای Origin توضیح میدهد. برای Payload بزرگ یا Query زیاد، IndexedDB معمولاً مناسبتر است.
| ریسک | کنترل |
|---|---|
| XSS به Storage دسترسی دارد | Token/Secret/PII حساس را ذخیره نکنید؛ CSP و AppSec |
| Schema تغییر میکند | Version، migration و fallback پاکسازی |
| State کهنه است | Timestamp/TTL و server reconcile |
| Quota/Private mode | Error handling و optional persistence |
| چند Tab | storage event/BroadcastChannel و conflict policy |
| User مشترک روی Device | Namespace per account و پاکسازی Logout |
Persist کردن کل Store آسان ولی خطرناک است: Loading/Error، Cache، Feature flag و Data کاربر قبلی را برمیگرداند. فقط State ضروری و Versioned را Allowlist کنید.
Auth و Session State؛ Client مرجع مجوز نیست
UI میتواند Capability را برای نمایش مناسب نگه دارد، اما Server باید Authentication و Authorization هر درخواست حساس را اجرا کند. isAdmin=true در Store مجوز نیست. Price، Discount، Stock و Order total نیز باید Server-side تأیید شوند.
- Session expiry و refresh/re-auth را مدل کنید؛
- Logout را در Tabها و Deviceهای لازم propagate کنید؛
- User switch باید Cache و persisted namespace را جدا کند؛
- خطای ۴۰۱، ۴۰۳ و Network error را یکی نکنید؛
- Token را در URL، Log، Redux DevTools یا persisted store نگذارید؛
- Hydration نباید Data کاربر دیگر را از Cache مشترک دریافت کند.
SSR، Server Components و Hydration
در SSR، State اولیه روی Server ساخته و روی Client Hydrate میشود. خطرها: Cache مشترک میان Requestها، Timestamp/Freshness متفاوت، Data غیرقابل Serialization، XSS در JSON و markup mismatch.
| قرارداد SSR | قاعده |
|---|---|
| Request isolation | Cache/Store User-specific per request |
| Serialization | Escape امن و type mapping صریح |
| Ownership | Server-rendered data را بیدلیل دوباره Client مالک نکند |
| Freshness | Fetched-at/stale policy مشترک |
| Hydration | Server/client snapshot سازگار |
| Error | Critical ۴۰۴/۵۰۰ با Loading silent یکی نشود |
راهنمای Advanced SSR در TanStack Query نیز بر Data ownership و Revalidation در Server Components و Hydration تأکید دارد. Framework و Version هدف را در Decision record ثبت کنید؛ الگوها با Rendering model تغییر میکنند.
Offline و PWA؛ Outbox و Conflict بخشی از State هستند
Offline-first فقط Persist کردن Cache نیست. باید Intentهای Write در Outbox ذخیره، ترتیب/Idempotency مدیریت، Connectivity تغییر و Conflict حل شود.
| جزء | وظیفه |
|---|---|
| Local snapshot | Read در Offline با Freshness label |
| Outbox | Commandهای Pending با ID و retry state |
| Sync engine | Backoff، ordering، auth refresh و resume |
| Conflict policy | Server wins، client wins، merge یا user choice |
| Reconciliation | Temporary ID، version و authoritative response |
برای Service Worker، Update lifecycle، Cache و SEO/Accessibility در PWA، راهنمای تصمیم و اجرای PWA مکمل این بخش است.
Performance؛ Subscription را اندازه بگیرید
Store بهخودیخود Performance را بهتر نمیکند. Context بزرگ، Selector ناپایدار، Object جدید، Subscription وسیع و update پر頻 میتوانند Render اضافی بسازند. در مقابل، بهینهسازی زودهنگام State را تکهتکه و Debug را سخت میکند.
| Metric | سؤال | ابزار |
|---|---|---|
| Commit/render duration | کدام update گران است؟ | Framework profiler |
| Render count | آیا Component بدون data change render شد؟ | Profiler/instrumentation |
| Selector cost | محاسبه یا allocation زیاد؟ | CPU profile |
| Store update rate | Event high-frequency کجاست؟ | Custom metric |
| Memory/cache size | GC/retention درست است؟ | Heap/cache inspector |
| Interaction latency | کاربر چه میبیند؟ | RUM/INP و trace |
برای پیوند Performance فنی به UX و Outcome، راهنمای سرعت سایت، UX و تبدیل را ببینید.
مقایسه ابزارها براساس مسئله، نه محبوبیت
| دسته | نمونه | نقطه قوت | هزینه/ریسک |
|---|---|---|---|
| Framework local | React state/reducer، Vue reactive | کمترین dependency و co-location | Cross-tree coordination |
| Context/Provide | React Context، Vue provide/inject | Distribution در Subtree | Update scope و hidden dependency |
| Structured global store | Redux Toolkit، Pinia | Convention، DevTools، team scale | Boilerplate/centralization |
| Minimal/atomic store | Zustand، Jotai و مشابه | API کوچک و subscription granular | Governance/fragmentation |
| Server cache | TanStack Query، RTK Query، SWR، Apollo | Freshness/invalidation/async lifecycle | Cache contract و defaults |
| State machine | Library یا reducer صریح | Transition/guard/impossible-state | مدلسازی و یادگیری |
مستندات رسمی Vue برای برنامههای جدید Pinia را توصیه میکند و SSR را یکی از دلایل نیاز به الگوی State management قویتر میداند. Recommendation هر اکوسیستم را در Version جاری بررسی کنید؛ «Redux پادشاه» یا «Zustand همیشه سریعتر» معیار معماری نیست.
معیار انتخاب ابزار State
| معیار | سؤال Pilot |
|---|---|
| State fit | UI، server cache، workflow یا external store؟ |
| Rendering model | CSR/SSR/streaming/server components؟ |
| Subscription | Granularity و concurrency semantics؟ |
| Async model | Cancellation/retry/invalidation/optimistic؟ |
| Type safety | Event/state impossible چگونه رد میشوند؟ |
| Debug | Timeline، reason، replay و redaction؟ |
| Test | Reducer/selector/integration بدون UI؟ |
| Bundle/runtime | هزینه واقعی روی route هدف؟ |
| Team | Convention، onboarding و ownership؟ |
| Exit | Domain logic از API کتابخانه جداست؟ |
دو Thin slice انتخاب کنید: یک Server query با optimistic mutation و یک Workflow چندمرحلهای. با داده واقعی، SSR/offline در صورت نیاز و ابزار Debug تیم Pilot کنید.
معماری نمونه فروشگاه ایرانی
| State | Owner/محل | نکته ایران |
|---|---|---|
| Query «کفش ورزشی» و Filter | URL | Unicode/نیمفاصله و share |
| Product/price/stock | Server query cache | تومان/ریال فقط نمایش؛ مبلغ authoritative Server |
| Cart drawer open | Local UI | Persist لازم نیست |
| Cart items | Server یا client projection با sync | Stock/price در Checkout دوباره تأیید |
| Address draft | Form + optional encrypted/limited persistence | PII و Device مشترک |
| Payment | Server order state machine | Pending/unknown/callback duplicate/reconciliation |
| Connectivity | External/browser signal | Network متغیر؛ offline label |
کاربر بعد از بازگشت از درگاه نباید فقط براساس Query string «موفق» ببیند. Client با Order ID وضعیت Server را میخواند؛ Pending را مدل و Callback/Query تکراری را Reconcile میکند.
امنیت و حریم خصوصی State
- Client state را ورودی بیاعتماد بدانید؛ Authorization و Price سمت Server؛
- Token/Secret/PII را در URL، Log، DevTools snapshot یا persistence نگذارید؛
- Cache key باید Tenant/User boundary را رعایت کند؛
- SSR cache را میان Userها Share نکنید؛
- State debug export قبل از ارسال به Support Redact شود؛
- Logout، account switch و consent withdrawal State مربوط را پاک/Invalidate کنند؛
- Third-party store/plugin را از نظر supply chain و update بررسی کنید.
برای BOLA، Token، OAuth، Webhook و Server-side authorization، راهنمای امنیت API را ببینید.
تست State؛ Transition و Concurrency را هدف بگیرید
| لایه | آزمون |
|---|---|
| Unit | Reducer/selector pure، transition و invariant |
| Contract | API schema، error mapping و version |
| Integration | Query→mutation→invalidate/reconcile |
| Concurrency | out-of-order، duplicate، cancel و two-tab |
| SSR/Hydration | request isolation، user switch و mismatch |
| Offline | reload، reconnect، outbox replay و conflict |
| E2E | Journey واقعی با slow/failed network |
Snapshot test بزرگ Store معمولاً دلیل Failure را پنهان میکند. Event و Invariant را تست کنید: «Paid هرگز به Submitting برنمیگردد» یا «Result مربوط به Query قبلی UI جدید را overwrite نمیکند».
Observability و Debug بدون نشت داده
Eventهای Domain، mutation ID، query key امن، cache hit/stale/refetch، transition، rollback، conflict و hydration error را قابل مشاهده کنید. Payload حساس را ثبت نکنید؛ Entity ID را در صورت نیاز Pseudonymize کنید.
| Signal | سؤال |
|---|---|
| Mutation failure/rollback | کدام Action و Error class؟ |
| Invalidation/refetch | چرا و چند Request ساخت؟ |
| Outbox depth/age | Offline writeها گیر کردهاند؟ |
| Conflict rate | کدام Entity/Journey؟ |
| Hydration mismatch | Server/client owner یا serialization؟ |
| Render/interaction | State update چه اثر UX داشت؟ |
برای Correlation، Sampling و کنترل Cardinality، راهنمای Observability سایت مکمل است.
مهاجرت از Store سراسری بدون بازنویسی بزرگ
- Inventory sliceها و Consumer/Writerها را بسازید؛
- هر State را طبقهبندی و Owner/Source of truth را مشخص کنید؛
- Derived data را حذف و Selector بسازید؛
- Server data را Feature-by-feature به Query layer منتقل کنید؛
- URL state را از Store بیرون ببرید؛
- UI local را به Component/Feature برگردانید؛
- Workflow را با Reducer/state machine مرزبندی کنید؛
- Adapter بسازید تا Consumerها یکباره تغییر نکنند؛
- Metric/Tests را قبل و بعد مقایسه و Slice قدیمی را حذف کنید.
Dual source of truth طولانی خطرناک است. برای هر مرحله یک Writer اصلی و تاریخ حذف Bridge تعیین کنید. Release را با CI/CD، Feature flag و Rollback کنترل کنید؛ راهنمای CI/CD امن الگوی Delivery را تکمیل میکند.
برنامه ۳۰روزه بهبود State
| بازه | خروجی | Gate |
|---|---|---|
| روز ۱ تا ۵ | Inventory، State type، Owner و duplicate map | Crown bugها و Source روشن |
| روز ۶ تا ۱۰ | State contract و query/cache policy | Freshness/concurrency/security تعریف |
| روز ۱۱ تا ۱۵ | Derived/URL/local extraction | Test و metric بدون Regression |
| روز ۱۶ تا ۲۲ | Server cache/optimistic/realtime contract | Failure/reconcile test پاس |
| روز ۲۳ تا ۲۷ | SSR/offline/persistence hardening | Isolation/migration/security پاس |
| روز ۲۸ تا ۳۰ | Decision record، conventions و roadmap | Owner و حذف legacy مشخص |
اشتباههای رایج مدیریت State
- Global store برای همهچیز: Scope و Lifetimeهای متفاوت مخلوط میشوند.
- Copy کردن Server response: Cache دوگانه و Invalidation ناقص میسازد.
- ذخیره Derived state: Sourceها از هم جدا میشوند.
- Effect برای Sync داخلی: Render اضافه و حالت واسط ناسازگار.
- چند Boolean برای Workflow: Impossible state تولید میشود.
- Persist کل Store: Token، Cache، User قبلی و Schema کهنه برمیگردند.
- Optimistic بدون Rollback: UI و Server واگرا میشوند.
- Realtime بدون Version/Resync: Event گمشده دیده نمیشود.
- SSR cache مشترک: خطر نشت داده میان Requestها.
- انتخاب با محبوبیت: مسئله State و Rendering model فراموش میشود.
- Memoization همهجا: پیچیدگی و Memory بدون Evidence.
- Client بهعنوان مرجع امنیت: Authorization/Price قابل دستکاری میشود.
سؤالات متداول درباره مدیریت State
چه زمانی به کتابخانه مدیریت State سراسری نیاز داریم؟
وقتی State واقعاً میان Featureهای دور مشترک است، Transition/Subscription و Debug قراردادی میخواهد و Local/Lift/URL/Query cache کافی نیست. Props drilling بهتنهایی دلیل قطعی نیست؛ Context یا Composition شاید مسئله را حل کند.
Redux بهتر است یا Context و Zustand؟
«بهتر» بدون نوع State معنی ندارد. Context کانال توزیع در Subtree، Redux Toolkit Store ساختاریافته با Convention/DevTools و ابزارهای مینیمال API/Subscription متفاوت دارند. Workload، SSR، async، team و Pilot را مقایسه کنید.
آیا داده API را داخل Redux یا Store عمومی بگذاریم؟
اغلب Query/cache layer مناسبتر است چون Freshness، retry، invalidation و GC را مدل میکند. اگر Redux دارید، RTK Query مسیر رسمی پیشنهادی همان اکوسیستم است. Domain client-only یا workflow ممکن است همچنان در Store بماند.
آیا localStorage برای سبد خرید و Login امن است؟
برای Token/Secret مناسب نیست چون JavaScript و XSS میتوانند آن را بخوانند. Cart ساده میتواند Projection محلی Versioned باشد، اما Price/Stock/Discount/Order باید Server-side تأیید و پس از Login/Tab sync Reconcile شوند.
چگونه از باگ Stateهای متناقض جلوگیری کنیم؟
State حداقلی، حذف duplicate/derived data، Union یا state machine برای Workflow، Eventهای صریح، Reducer pure، Version/Idempotency برای async و تست Invariant/Concurrency بهترین پایهاند.
جمعبندی: ابزار آخرین تصمیم است
مدیریت State خوب از Ownership و Consistency شروع میشود. برای هر داده Identity، Owner، Scope، Lifetime، Mutation، Freshness، Concurrency، Security و Failure را تعریف کنید؛ سپس آن را در سادهترین محل معتبر—Render، Server، URL، Component، Query cache، Reducer یا Store—قرار دهید. این کار هم باگ را کم میکند و هم مهاجرت ابزار را سادهتر نگه میدارد.
اگر برای Audit State، طراحی Cache/SSR/Offline یا انتخاب و مهاجرت Store نیاز به همراهی دارید، از فرم درخواست مشاوره مایندیو معماری، Framework، Journeyهای حساس و نمونه باگهای فعلی را بفرستید.
مطالب مرتبط
- API وب؛ قرارداد، خطا و قابلیت اطمینان
- معماری Cache در اپلیکیشن وب
- سرعت سایت، UX و Outcome
- Observability با Metric، Log و Trace
- CI/CD امن و Progressive delivery
- امنیت API، OAuth و JWT
- راهنمای تصمیم و اجرای PWA






