8 মিনিট

কেন স্টেট ম্যানেজমেন্ট ফ্রন্টএন্ডের সবচেয়ে কঠিন সমস্যাগুলোর একটি

স্টেট ম্যানেজমেন্ট কঠিন কারণ অ্যাপে বহু সত্যের উৎস, অ্যাসিঙ্ক ডেটা, UI ইন্টারঅ্যাকশন, এবং পারফরম্যান্স ট্রেডঅফ থাকে। বাগ কমানোর প্যাটার্নগুলো শিখুন।

কেন স্টেট ম্যানেজমেন্ট ফ্রন্টএন্ডের সবচেয়ে কঠিন সমস্যাগুলোর একটি

একটি ফ্রন্টএন্ড অ্যাপে “স্টেট” আসলে কী বোঝায়

সাধারণ ভাষায় সংজ্ঞা

একটি ফ্রন্টএন্ড অ্যাপে স্টেট হলো সহজভাবে ওই ডেটা যার ওপর আপনার UI নির্ভর করে এবং যেটি সময়ের সাথে বদলে যেতে পারে

স্টেট বদলালে স্ক্রিনও মিলিয়ে আপডেট হওয়া উচিত। যদি স্ক্রিন আপডেট না হয়, অনিয়মিতভাবে আপডেট হয়, বা পুরোনো ও নতুন মানের মিশ্রণ দেখায়, তখনই আপনি “স্টেট সমস্যা” অনুভব করবেন — বোতামগুলো ডিসেবলেড থেকে যায়, মোটগুলো মেলে না, বা ভিউটি ব্যবহারকারীর সাম্প্রতিক কাজ প্রতিফলিত করে না।

প্রতিদিন যে সাধারণ উদাহরণগুলো দেখেন

স্টেট ছোট ও বড় দুটো ইন্টারঅ্যাকশনে উভয়েই আসে, যেমন:

  • ফর্ম ইনপুট: ব্যবহারকারী কী টাইপ করেছে, কোন চেকবক্স চেক করা আছে, কোন এরর দেখাবেন
  • নেভিগেশন পছন্দ: নির্বাচিত ট্যাব, উইজার্ডে বর্তমান ধাপ, এক্সপ্যান্ড/কল্যাপ্স করা সেকশন
  • শপিং/কার্ট ডেটা: আইটেম, পরিমাণ, প্রয়োগ করা কুপন, গণনা করা মোট
  • ইউজার সেশন: লগ-ইন করা ইউজার তথ্য, পারমিশন, ফিচার ফ্ল্যাগ, “রিমেম্বার মি” পছন্দ

এইগুলোর কিছু “অস্থায়ী” (যেমন একটি নির্বাচিত ট্যাব), আবার কিছু “গুরুত্বপূর্ণ” (যেমন কার্ট)। এগুলো সবই স্টেট কারণ এগুলোই নির্ধারণ করে UI এখন কী রেন্ডার করবে।

কেন স্টেট শুধু “কম্পোনেন্টের ভেরিয়েবল” নয়

একটি সাধারণ ভেরিয়েবল শুধু যেখানে থাকে সেই জায়গায়ই প্রাসঙ্গিক। স্টেট আলাদা কারণ এটির কিছু নিয়ম আছে:

  • অধিকার: অ্যাপের কোন অংশ এটিকে পরিবর্তন করার অনুমতি পায়
  • আপডেট ফ্লো: কখন এবং কিভাবে পরিবর্তনগুলো রি-রেন্ডার ট্রিগার করে
  • সামঞ্জস্যতা: একাধিক UI অংশ সিঙ্ক থেকে বিচ্যুত না হওয়া নিশ্চিত করা

স্টেট ম্যানেজমেন্টের আসল লক্ষ্য ডেটা সংরক্ষণ করা নয়—এটি আপডেটগুলোকে পূর্বানুমেয় করা যাতে UI সামঞ্জস্যপূর্ণ থাকে। যখন আপনি উত্তর দিতে পারেন “কি বদলেছে, কখন, এবং কেন,” তখন স্টেট নিয়ন্ত্রণযোগ্য হয়। যখন পারেন না, তখন সাধারণ ফিচারগুলোও আশ্চর্যের কারণ হয়ে দাঁড়ায়।

কেন স্টেট প্রথমে সহজ লাগে (তারপর হঠাৎ জটিল হয়)

প্রকল্প শুরুতে স্টেট প্রায় নীরসভাবে সহজ লাগে—ভালো অর্থে। আপনার একটি কম্পোনেন্ট, একটি ইনপুট, এবং একটি স্পষ্ট আপডেট আছে। ব্যবহারকারী একটি ফিল্ডে টাইপ করে, আপনি সেই মান সেভ করেন, UI রি-রেন্ডার করে। সবকিছু দৃশ্যমান, অবিলম্বে, এবং সীমাবদ্ধ।

সহজ কেস: এক কম্পোনেন্ট, এক আপডেট

একটি টেক্সট ইনপুট কল্পনা করুন যা আপনি টাইপ করলে তার প্রিভিউ দেখায়:

  • স্টেট সেই একই কম্পোনেন্টে থাকে যা ইনপুট রেন্ডার করে।
  • আপডেট সরাসরি ব্যবহারকারীর কাজের প্রতিক্রিয়ায় ঘটে।
  • “কে ডেটা ধারণ করে” নিয়ে কোনো বিতর্ক নেই।

এই সেটআপে স্টেট মূলত: একটি ভেরিয়েবল যা সময়ের সাথে বদলায়। আপনি বলতে পারবেন কোথায় রাখা আছে এবং কোথায় আপডেট হচ্ছে, আর হলেন।

কেন লোকাল কম্পোনেন্ট স্টেট সোজা লাগে

লোকাল স্টেট কাজ করে কারণ মানসিক মডেল কোড স্ট্রাকচারের সাথে মিলে যায়:

  • স্কোপ ছোট (একটি কম্পোনেন্ট, সম্ভবত কিছু চাইল্ড)
  • ব্যবহারকারীর দৃষ্টিকোণ থেকে আপডেটসমূহ সিঙ্ক্রোনাস
  • ডেটা ফ্লো স্পষ্ট: ইনপুট → আপডেট → রেন্ডার

এমনকি যদি আপনি React-এর মতো ফ্রেমওয়ার্ক ব্যবহার করেন, আর্কিটেকচারের ব্যাপারে গভীরভাবে ভাবতে হয় না। ডিফল্টগুলো যথেষ্ট।

অ্যাপ বাড়লে কী বদলায়

জবারই অ্যাপ “একটি উইজেটের পেজ” থেকে “একটি প্রোডাক্ট” হয়ে ওঠে, স্টেট আর এক জায়গায় থাকে না।

একই ডেটা এখন বিভিন্ন জায়গায় লাগতে পারে:

  • একাধিক স্ক্রিনে (নেভিগেশন)
  • দূরের কম্পোনেন্টগুলোতে (শেয়ার করা UI)
  • রিলোড ও রিস্টার্টে (পারসিস্টেন্স)
  • একাধিক ব্যবহারকারী/ডিভাইসে (সার্ভার সিঙ্করণ)

একটি প্রোফাইল নাম হেডারে দেখানো হতে পারে, সেটিংসে এডিট করা হতে পারে, দ্রুত লোড করার জন্য ক্যাশ করা হতে পারে, এবং ওয়েলকাম মেসেজ পার্সোনালাইজ করতে ব্যবহার হতে পারে। হঠাৎ করে প্রশ্ন হয় কীভাবে রাখলে সব জায়গায় সঠিক থাকবে।

জটিলতা নন-লাইনারভাবে বেড়ে যায়

স্টেট জটিলতা ধীরে বেড়ে না—এটি একপ্রকার লাফ দেয়।

একই ডেটা পড়ার আরেকটা জায়গা যোগ করলেই এটা “দুই গুণ কঠিন” হয় না। এটি সমন্বয় সমস্যা নিয়ে আসে: ভিউগুলিকে কনসিস্টেন্ট রাখা, স্টেইল মান প্রতিরোধ করা, কে কি আপডেট করবে সিদ্ধান্ত নেওয়া, এবং টাইমিং হ্যান্ডল করা। কয়েকটি শেয়ার করা স্টেট ও অ্যাসিঙ্ক কাজ থাকলেই আচরণ বোঝা কঠিন হয়ে যেতে পারে—যদিও প্রতিটি ফিচার নিজেই সাধারণই লাগছে।

অনেকগুলো সত্যের উৎস (Too Many Sources of Truth)

একই “তথ্য” একাধিক জায়গায় রাখা হলে স্টেট কষ্টদায়ক হয়ে যায়। প্রতিটি কপি় বিচ্যুত হতে পারে, এবং এখন আপনার UI নিজে থেকেই বিরোধ শুরু করে।

প্রচলিত সন্দেহভাজনগণ

বহু অ্যাপেই সাধারণত কয়েকটি জায়গা থাকে যেখানে “তথ্য” থাকতে পারে:

  • সার্ভার ডেটা (আপনার API/ডাটাবেস): canonical রেকর্ড
  • ক্লায়েন্ট ক্যাশ (যেমন ডেটা ফেচিং লাইব্রেরির ক্যাশ): লোকাল মিরর যা রিফ্রেশ করা হয়
  • লোকাল UI স্টেট (কম্পোনেন্ট স্টেট): ব্যবহারকারী এখন কী করছে
  • URL (পাথ, কুয়ারি প্যারাম, হ্যাশ): সেই স্টেট যা বুকমার্ক, শেয়ার ও পুনরুদ্ধার করা যায়

এসবের প্রতিটিই কোনো না কোনো স্টেটের জন্য বৈধ মালিক হতে পারে। সমস্যা শুরু হয় যখন সবগুলোই একই স্টেটকে নিজেদের মালিক বানাতে চায়।

কপি কিভাবে ঘটে

একটি সাধারণ প্যাটার্ন: সার্ভার থেকে ডেটা ফেচ করে সেটিকে লোকাল স্টেটে কপি করা “তাই যে আমরা এডিট করতে পারি”। উদাহরণ: আপনি ইউজার প্রোফাইল লোড করে formState = userFromApi সেট করেন। পরে সার্ভার রিফেচ করে (অথবা আরেকটি ট্যাব রেকর্ড আপডেট করে), তখন আপনার কাছে দুইটি ভেরিয়েন্ট থাকে: ক্যাশ একটি বলে আর আপনার ফর্ম আরেকটি।

ডুপ্লিকেশন “সহায়ক” ট্রান্সফর্মেশনের মাধ্যমে ও ঘসে পড়ে: items এবং itemsCount একসঙ্গে রাখা, বা selectedId এবং selectedItem একই কারণে রাখা।

আপনি যে লক্ষণগুলো চিনবেন

একাধিক সত্য উৎস থাকলে বাগগুলোর সাধারণ কণ্ঠ হয়:

  • “এটা শুধু এই স্ক্রিনে কাজ করে।”
  • নেভিগেশন বা রিফ্রেশের পরে UI কনসিস্টেন্ট নয়।
  • এক কম্পোনেন্টে ডেটা ঠিক আছে কিন্তু অন্যটিতে স্টেইল লাগছে।
  • সেভ হওয়া সাফল্যের দেখায়, কিন্তু লিস্ট ভিউ আপডেট হয় না (বা দ্বিগুণ আপডেট হয়)।

নিয়মের সাধারণ ব্যাখ্যা

প্রতিটি স্টেটের জন্য একটি মালিক পয়েন্ট করুন—যেখানে আপডেট করা হয়—এবং বাকিদেরকে প্রজেকশন হিসেবে বিবেচনা করুন (রিড-ওনলি, ড্যারাইভড, বা একদিকে-সিঙ্ক)। আপনি যদি মালিককে পয়েন্ট করতে না পারেন, তাহলে সম্ভবত একই সত্য আপনি দুবারই স্টোর করছেন।

অ্যাসিঙ্ক কাজ ও সাইড-ইফেক্ট স্টেটকে জটিল করে

অনেক ফ্রন্টএন্ড স্টেট সহজ লাগে কারণ তা সিঙ্ক্রোনাস: ব্যবহারকারী ক্লিক করে, আপনি মান সেট করেন, UI আপডেট করে। সাইড-ইফেক্ট সেই ধারাবাহিক গল্প ভাঙে।

সাইড-ইফেক্ট বলতে কী বোঝায়?

সাইড-ইফেক্ট হলো যেকোনো অ্যাকশন যা আপনার কম্পোনেন্টের পিউর “ডেটার ওপর রেন্ডার” মডেলের বাইরে যায়:

  • নেটওয়ার্ক কল (ফেচ, সেভ, রিট্রাই)
  • টাইমার এবং ডেবান্সিং (setTimeout, intervals)
  • সাবস্ক্রিপশন (ওয়েবসকেট, ইভেন্ট লিসেনার)
  • ব্রাউজার স্টোরেজ (localStorage/sessionStorage)

প্রতিটি কখনোও পরে ফায়ার হতে পারে, অকল্পনীয়ভাবে ব্যর্থ হতে পারে, বা বারবার চালাতে পারে।

অ্যাসিঙ্ক স্টেট কেন সিঙ্ক স্টেটের চেয়ে কঠিন

অ্যাসিঙ্ক আপডেটগুলো সময়কে একটি ভ্যারিয়েবল হিসেবে পরিণত করে। আপনি আর “কি ঘটেছে” নিয়ে চিন্তা করেন না, বরং “কি সম্ভবত এখনো ঘটছে” নিয়ে চিন্তা করেন। দুটি রিকোয়েস্ট overlap করতে পারে। একটি ধীর রেসপন্স নতুনটির পরে আসতে পারে। একটি কম্পোনেন্ট আনমাউন্ট হওয়ার সময়ও একটি অ্যাসিঙ্ক কল স্টেট আপডেট করতে পারে।

এই কারণে বাগগুলো সাধারণত এরকম দেখায়:

  • লোডিং ফ্ল্যাগ চিরতরে আটকে থাকে (এরর পাথ সেগুলো ক্লিয়ার করেনি বা রিকোয়েস্ট বাতিল হয়নি)
  • UI পুরোনো ডেটা ফ্ল্যাশ করে (স্টেইল ক্যাশ করা মান “চূড়ান্ত” হিসেবে দেখানো)
  • পুরোনো রেসপন্স নতুনটিকে ওভাররাইট করে (রিকোয়েস্ট A শেষ হয় রিকোয়েস্ট B-এর পরে)

একটি সহজ কৌশল: রিকোয়েস্টকে স্পষ্টভাবে মডেল করুন

বিভিন্ন জায়গায় isLoading মতো বুলিয়ান ছড়িয়ে দেওয়ার বদলে অ্যাসিঙ্ক কাজকে একটি ছোট স্টেট মেশিন হিসেবে বিবেচনা করুন:

  • idle (কিছু শুরু হয়নি)
  • loading (চলছে)
  • success (ডেটা পাওয়া গেছে)
  • error (ব্যর্থতা ধরা হয়েছে)

ডেটা এবং স্ট্যাটাস একসাথে ট্র্যাক করুন, এবং একটি আইডেন্টিফায়ার (রিকোয়েস্ট আইডি বা কুয়েরি কী) রাখুন যাতে আপনি দেরিতে আসা রেসপন্সগুলো উপেক্ষা করতে পারেন। এভাবে “এখন UI কী দেখাবে?” প্রশ্নটি সম্ভাব্যতার বদলে একটি সরল সিদ্ধান্ত হবে।

UI স্টেট বনাম সার্ভার স্টেট (দুইটি একই রকম দেখলেও আলাদা)

অনেক স্টেট সমস্যা একটি সহজ মিশআপ থেকেই শুরু: “যে মুহূর্তে UI কী করছে” কে “যে সার্ভার বলে সত্য” এর সাথেই মিলিয়ে ফেলা। উভয়ই সময়ের সাথে বদলে যেতে পারে, কিন্তু তাদের নিয়ম আলাদা।

UI স্টেট: ইন্টারফেস এখন কী করছে

UI স্টেট অস্থায়ী এবং ইন্টারঅ্যাকশন চালিত। এটি সেই মুহূর্তে স্ক্রিনকে ব্যবহারকারীর প্রত্যাশা অনুযায়ী রেন্ডার করার জন্য থাকে।

উদাহরণ: মডাল ওপেন/ক্লোজ, একটিভ ফিল্টার, সার্চ ইনপুট ড্রাফট, হোভার/ফোকাস, কোন ট্যাব নির্বাচিত, পেজিনেশন UI (কারেন্ট পেজ, পেজ সাইজ, স্ক্রল পজিশন)।

এই স্টেট সাধারণত পেজ বা কম্পোনেন্ট ট্রির লোকাল। নেভিগেট করলে রিসেট হওয়াও ঠিক আছে।

সার্ভার স্টেট: আপনি যা ফেচ করেছেন (এবং অন্যত্র বদলাতে পারে)

সার্ভার স্টেট হলো API থেকে আসা ডেটা: ইউজার প্রোফাইল, প্রোডাক্ট লিস্ট, পারমিশন, নোটিফিকেশন, সেভ করা সেটিংস। এটা “রিমোট ট্রুথ” যা আপনার UI কিছু না করলেই বদলে যেতে পারে (কেউ অন্যজন এটাকে এডিট করে, সার্ভার এটা পুনরপরিগণনা করে, ব্যাকগ্রাউন্ড জব আপডেট করে)।

কারণ এটি রিমোট, তাই এটাকে লোডিং/এরর স্টেট, ক্যাশ টাইমস্ট্যাম্প, রিট্রাই, এবং ইনভ্যালিডেশন মতো মেটাডেটাও দরকার।

কেন মিশালে বিভ্রান্তি হয়

যদি আপনি UI ড্রাফটকে সার্ভার ডেটার ভিতরে স্টোর করেন, একটি রিফেচ লোকাল এডিট মুছে দিতে পারে। যদি আপনি সার্ভার রেসপন্সকে UI স্টেটে স্টোর করেন কিন্তু কোনো ক্যাশ নিয়ম না রাখেন, আপনি স্টেইল ডেটা, ডুপ্লিকেট ফেচ, এবং অসামঞ্জস্যপূর্ণ স্ক্রিন পাবেন।

একটি সাধারণ ব্যর্থ মোড: ব্যবহারকারী একটি ফর্ম এডিট করছে, তখন ব্যাকগ্রাউন্ড রিফেচ শেষ হয় এবং ইনকামিং রেসপন্স ড্রাফটকে ওভাররাইট করে ফেলে।

ব্যবহারিক নির্দেশনা

সার্ভার স্টেটকে ক্যাশিং প্যাটার্ন দিয়ে ম্যানেজ করুন (ফেচ, ক্যাশ, ইনভেলিডেট, ফোকাসে রিফেচ) এবং এটাকে শেয়ার্ড ও অ্যাসিঙ্ক্রোনাস হিসেবে বিবেচনা করুন।

UI স্টেটকে লোকাল টুল দিয়ে ম্যানেজ করুন (লোকাল কম্পোনেন্ট স্টেট, কনটেক্সট যখন সত্যিই শেয়ার করা UI কনসার্ন থাকে), এবং ড্রাফটগুলো আলাদা রাখুন যতক্ষণ না আপনি ইচ্ছাকৃতভাবে সেগুলো সার্ভারে “সেভ” করছেন।

উৎপন্ন স্টেট (Derived State) এবং “যা গণনা করা যায় তা স্টোর করবেন না” নীতি

প্রোডাকশনে স্টেট পরীক্ষা করুন
বাস্তব ব্যবহারে লোডিং, ত্রুটি এবং রেস কন্ডিশন যাচাই করতে আপনার প্রোটোটাইপ ডিপ্লয় করুন।

উৎপন্ন স্টেট হলো এমন কোন মান যা অন্য স্টেট থেকে গণনা করা যায়: কার্টের মোট লাইন আইটেম থেকে, ফিল্টার করা লিস্ট মূল লিস্ট + সার্চ কুয়েরি থেকে, কিংবা canSubmit ফিল্ড মান ও ভ্যালিডেশন রুল থেকে।

এগুলো স্টোর করা আকর্ষণীয় কারণ সুবিধাজনক মনে হয় (“আমি totalও স্টেটে রাখব”)। কিন্তু ইনপুটগুলো একাধিক জায়গায় বদলে গেলে ড্রিফটের ঝুঁকি দেখা দেয়: স্টোর করা total আইটেমগুলোর মেলে না, ফিল্টারড লিস্ট বর্তমান কুয়েরির সাথে মেলে না, বা সাবমিট বাটন একটি এরর ঠিক করার পরেও ডিসেবলেড থেকে যায়। এই বাগগুলো বিরক্তিকর কারণ একাই কোনো ভেরিয়েবল “ভুল” দেখায় না—প্রতিটি পৃথক ভেরিয়েবল নিজে ভ্যালিড, কিন্তু একে অপরের সাথে অসামঞ্জস্যপূর্ণ।

সিলেক্টর / কম্পিউটেড ভ্যালুগুলো প্রেফার করুন

নিরাপদ প্যাটার্ন: মিনিমাল সোর্স অফ ট্রুথ স্টোর করুন, এবং বাকিটা পড়ার সময় গণনা করুন। React-এ এটি একটি সাধারণ ফাংশন হতে পারে, বা মেমোইজড ক্যালকুলেশন।

const items = useCartItems();
const total = items.reduce((sum, item) =\u003e sum + item.price * item.qty, 0);

const filtered = products.filter(p =\u003e p.name.includes(query));

বড় অ্যাপগুলোতে “সিলেক্টর” বা কম্পিউটেড গেটারগুলো এই ধারণাকে রূপরেখা দেয়: এক জায়গায় total, filteredProducts, visibleTodos কিভাবে ডেরাইভ করা হয় তা সংজ্ঞায়িত করুন এবং প্রতিটি কম্পোনেন্ট একই লজিক ব্যবহার করুক।

কবে উৎপন্ন ভ্যালুগুলো ক্যাশ করা ঠিক

প্রতি রেন্ডারে গণনা করা সাধারণত ঠিক আছে। তখনই ক্যাশ করুন যখন বাস্তব খরচ পরিমাপ করে দেখেন: ব্যয়বহুল ট্রান্সফরমেশন, বিশাল লিস্ট, অথবা বহু কম্পোনেন্টে শেয়ার করা ডেরাইভড ভ্যালু। মেমোইজেশন (useMemo, সিলেক্টর মেমোইজেশন) ব্যবহার করুন যাতে ক্যাশ কীগুলো সঠিক ইনপুটগুলোর উপর ভিত্তি করে থাকে—নাহলে আপনি আবার ড্রিফট নিয়ে ফিরবেন, কেবল পারফরম্যান্সের ঝাঁপ তুলে।

গ্লোবাল বনাম লোকাল: সঠিক মালিক নির্বাচন করা

স্টেট কষ্টদায়ক হয় যখন এটা অস্পষ্ট হয়ে যায় কে অধিকারী

“অধিকার” মানে কী

কোনো স্টেটের অধিকারী হল সেই জায়গা যেখানে স্টেট আপডেট করার অধিকার আছে। অন্য অংশগুলো সেটি পড়তে পারে (প্রপস, কনটেক্সট, সিলেক্টর ইত্যাদি মারফত), কিন্তু সরাসরি বদলানো উচিত নয়।

স্পষ্ট অধিকার দুইটি প্রশ্নের উত্তর দেয়:

  • কে এই মান আপডেট করতে পারে? (মালিক)
  • কে এই মান পড়তে পারে? (কনজিউমাররা)

যখন এসব সীমানা ধূসর হয়, আপনি কনফ্লিক্টেড আপডেট, “টা কেন বদললো?” মুহূর্ত, এবং রিইউজ করা কঠিন কম্পোনেন্ট পান।

গ্লোবাল স্টেট: সুবিধাজনক, কিন্তু কাপলিং ঢুকতে পারে

স্টেট গ্লোবাল স্টোর বা টপ-লেভেল কনটেক্সটে রাখা পরিষ্কার মনে হতে পারে: যেকোনো জিনিস এটি অ্যাক্সেস করতে পারে, প্রপ ড্রিল দূর হয়। ট্রেডঅফ হলো অনিচ্ছাকৃত কাপলিং—হঠাৎ করে সম্পর্কহীন স্ক্রিনগুলো একই ভ্যালুর উপর নির্ভর করতে শুরু করে, এবং ছোট পরিবর্তনও পুরো অ্যাপ জুড়ে ঢেউ তুলতে পারে।

গ্লোবাল স্টেট উপযুক্ত যেখানে সত্যিই ক্রস-কাটিং কনসার্ন আছে, যেমন কারেন্ট ইউজার সেশন, অ্যাপ-ওয়াইড ফিচার ফ্ল্যাগ, বা শেয়ার্ড নোটিফিকেশন কিউ।

স্টেট লিফট করুন—শুধু যেখানে প্রয়োজন

একটি সাধারণ প্যাটার্ন: লোকাল থেকে শুরু করে সেই নিকটতম কমন পেরেন্ট পর্যন্ত স্টেট লিফট করুন যখন দুটো সাইব্লিং অংশে সমন্বয় প্রয়োজন।

যদি কেবল একটি কম্পোনেন্টের প্রয়োজন থাকে, সেখানে রাখুন। যদি একাধিক কম্পোনেন্টের প্রয়োজন হয়, সবচেয়ে ছোট শেয়ারড মালিক পর্যন্ত লিফট করুন। যদি বহু দূরবর্তী এলাকায় দরকার হয়, তখনই গ্লোবাল বিবেচনা করুন।

সরল হিউরিস্টিক

স্টেট যেখানে ব্যবহার হয় সেখানে যত কাছাকাছি রাখুন যতক্ষণ না শেয়ারিং প্রয়োজন।

এটি কম্পোনেন্টগুলিকে বোঝা সহজ রাখে, অনিচ্ছাকৃত ডিপেনডেন্সি কমায়, এবং ভবিষ্যতের রেফ্যাক্টরিং কম ভয়ানক করে কারণ কম ফাইলেই পরিবর্তন লাগে।

কনকারেন্সি, রেস, এবং অর্ডারের বাইরে আপডেট

স্টেট মডেল পরিকল্পনা করুন
কোড লিখার আগে মালিকানা, সার্ভার স্টেট এবং সূত্রানুসৃত মান নির্ধারণ করতে Planning Mode ব্যবহার করুন।

ফ্রন্টএন্ড অ্যাপগুলো “সিঙ্গল-থ্রেডেড” মনে হলেও ব্যবহারকারী ইনপুট, টাইমার, অ্যানিমেশন, এবং নেটওয়ার্ক সবই স্বাধীনভাবে চলে। এর মানে একাধিক আপডেট একই সময়ে চলতে পারে—এবং এগুলো যে ক্রমে শুরু হয় ঠিক সেই ক্রমে শেষ না-ও হতে পারে।

আপডেটগুলো সংঘর্ষ করলে কী হয়

একটি সাধারণ সংঘর্ষ: UI-এর দুটি অংশ একই স্টেট আপডেট করে।

  • একটি সার্চ বক্স প্রতি কীস্ট্রোকে query আপডেট করে।
  • একটি ফিল্টার ড্রপডাউন একই query (অথবা একই রেজাল্ট লিস্ট) আপডেট করে।

প্রত্যেকে আলাদাভাবে সঠিক, কিন্তু একসাথে তারা টাইমিং অনুসারে একে অপরকে ওভাররাইট করে দিতে পারে। এমনকি খারাপ হলে আপনি নতুন ফিল্টার দেখাচ্ছেন অথচ রেজাল্ট হচ্ছে আগের কুয়েরির জন্য।

রেস কন্ডিশন: দ্রুত ব্যবহারকারী, ধীর নেটওয়ার্ক

রেস কন্ডিশন তখনই দেখা দেয় যখন আপনি রিকোয়েস্ট A চালান, তারপর দ্রুত রিকোয়েস্ট B চালান—কিন্তু রিকোয়েস্ট A পরে ফিরে আসে।

উদাহরণ: ব্যবহারকারী টাইপ করে “c”, “ca”, “cat”。 যদি “c” রিকোয়েস্ট ধীর হয় এবং “cat” দ্রুত হয়, UI প্রথমে “cat” ফল দেখাতে পারে এবং পরে স্টেইল “c” ফল দ্বারা ওভাররাইট হয়ে যেতে পারে।

বাগ সূক্ষ্ম কারণ সবকিছু “কার্যকর” ছিল—শুধু ভুল ক্রমে।

আউট-অফ-অর্ডার বাগগুলো কমানোর কৌশল

সাধারণত নিচের কোন একটি কৌশল প্রয়োগ করতে চান:

  1. আগের রিকোয়েস্ট বাতিল করুন যখন নতুনটি আসে (উদাহরণ: AbortController)।
  2. স্টেইল রেসপন্স উপেক্ষা করুন চেক করে যে রেসপন্স এখনও লেটেস্ট ইনপুটের সাথে মিলছে কি না।
  3. রিকোয়েস্ট আইডি / সিকোয়েন্স নাম্বার ব্যবহার করুন এবং কেবল লেটেস্টকে গ্রহণ করুন।

একটি সরল রিকোয়েস্ট আইডি পদ্ধতি:

let latestRequestId = 0;

async function fetchResults(query) {
  const requestId = ++latestRequestId;
  const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
  const data = await res.json();

  if (requestId !== latestRequestId) return; // stale response
  setResults(data);
}

অপটিমিস্টিক আপডেট (এবং কীভাবে এগুলো ভেঙে যায়)

অপটিমিস্টিক আপডেট UI-কে তাত্ক্ষণিক অনুভব করায়: আপনি সার্ভারের কনফার্মেশনের আগে সবার আগে স্ক্রিন আপডেট করেন। কিন্তু কনকারেন্সি ধারণাগুলো ভাঙতে পারে:

  • ব্যবহারকারী দ্রুত “লাইক” দুইবার ক্লিক করে (লাইক → আনলাইক), কিন্তু রিকোয়েস্টগুলো অর্ডারে রিসল্ভ না হলে সমস্যা হয়।
  • আপনি অপটিমিস্টিকভাবে ইনভেন্টরি কমিয়ে দিলেন, পরে একটি ব্যর্থতা ঘটলে রোলব্যাক দরকার—কিন্তু ব্যবহারকারী ইতিমধ্যেই চলে গেছে বা আরো পরিবর্তন করেছে।

অপটিমিজমকে নিরাপদ রাখার জন্য সাধারণত স্পষ্ট রিকনসিলিয়েশন নিয়ম দরকার: পেন্ডিং অ্যাকশন ট্র্যাক করুন, সার্ভার রেসপন্সকে সঠিক ক্রমে প্রয়োগ করুন, এবং যদি রোলব্যাক করতে হয়, তাহলে একটি জানা চেকপয়েন্টে রোলব্যাক করুন (এখনকার UI-র অবস্থা নয়)।

পারফরম্যান্স: যখন স্টেট পরিবর্তন খুব ব্যয়বহুল হয়

স্টেট আপডেটগুলো “ফ্রি” নয়। স্টেট বদলালে অ্যাপকে ঠিক কোন UI অংশ প্রভাবিত হতে পারে তা নির্ণয় করে তা প্রতিফলিত করার কাজ করতে হয়: মান পুনঃগণনা, UI রি-রেন্ডার, ফরম্যাটিং লজিক পুনরায় চালানো, এবং কখনো কখনো পুনরায় ফেচ বা ভ্যালিডেশন। যদি সেই চেইন প্রতিক্রিয়া অবাঞ্ছিতভাবে বড় হয়, ব্যবহারকারী এটিকে ল্যাগ, জ্যাঙ্ক, বা বোতামগুলো “চিন্তা করছে” হিসেবে অনুভব করবে।

কেন একটি ছোট পরিবর্তন বড় মনে হতে পারে

একটি টগল নিছকেই অনেক অতিরিক্ত কাজ ট্রিগার করতে পারে:

  • UI-এর বড় অংশ রি-রেন্ডার করে যদিও মাত্র একটি ছোট অংশ পরিবর্তিত হয়েছে।
  • লিস্টগুলো পুনরায় ড্র করে এবং রি-মেজার করে, স্ক্রলিং-এ ঝাটকা ঘটায়।
  • অবজেক্ট ও অ্যারে প্রতিটি আপডেটে পুনরায় তৈরি হয় (“ডীপ চর্ন”), তাই অ্যাপ সহজে আলাদা করে বলতে পারে না কি সত্যিই বদলেছে।

ফলাফল কেবল টেকনিক্যাল নয়—এটি অভিজ্ঞতাগত: টাইপিং ধীর লাগে, অ্যানিমেশন হেঁচে যায়, এবং ইন্টারফেস সেই “স্ন্যাপক” গুণ হারায় যা মানুষ ভাল প্রোডাক্টে প্রত্যাশা করে।

সাধারণ পারফরম্যান্স ফাঁদ

একটি সাধারণ কারণ হল স্টেট খুবই ব্যাপক: অনেক অনৈক্য বিষয় এক জায়গায় রাখা। কোনো ফিল্ড আপডেট করলেই পুরো বাকেট নতুন দেখায়, ফলে UI-এর বেশি অংশ জাগে।

আরেকটি ফাঁদ হলো গণিত করা ভ্যালুগুলো স্টেটে রাখা এবং ম্যানুয়ালি আপডেট করা—এটা প্রায়ই অতিরিক্ত আপডেট তৈরি করে (আরও UI কাজ) কেবল সবকিছু সিঙ্ক রাখতে।

UI-কে দ্রুত রাখার কৌশল

স্টেটকে ছোট স্লাইসে ভাগ করুন। অপ্রাসঙ্গিক কনসার্ন আলাদা রাখুন যাতে সার্চ ইনপুট পরিবর্তন করে পুরো পেজ রিফ্রেশ না করে।

ডেটা নরমালাইজ করুন। একই আইটেম অনেক জায়গায় রাখার বদলে একবার রাখুন এবং রেফারেন্স করে ব্যবহার করুন। এতে রিপিটেড আপডেট কমে এবং “চেঞ্জ স্টর্ম” প্রতিরোধ হয় যেখানে একটি এডিট অনেক কপিকে পুনরায় লেখে।

ডেরাইভড ভ্যালুগুলো মেমোইজ করুন। যদি একটি ভ্যালু অন্য স্টেট থেকে গণনা করা যায় (যেমন ফিল্টার করা রেজাল্ট), সেটি ক্যালকুলেশন ক্যাশ করুন যাতে কেবল ইনপুটগুলো বদলালে পুনরায় কম্পিউট হয়।

লক্ষ্য: কম স্টল, কম অপ্রত্যাশিততা

ভালো পারফরম্যান্সমাইন্ডেড স্টেট ম্যানেজমেন্ট প্রধানত কন্টেইনমেন্ট সম্পর্কিত: আপডেটগুলো সবচেয়ে ছোট সম্ভব এলাকায় প্রভাব ফেলুক, এবং ব্যয়বহুল কাজ শুধুমাত্র তখনই হোক যখন সত্যিই প্রয়োজন। যখন এটা সত্য, ব্যবহারকারীরা ফ্রেমওয়ার্ককে আর লক্ষ্য করে না এবং ইন্টারফেসে বিশ্বাস করে।

স্টেট ডিবাগ এবং টেস্টিং অনুমান ছাড়াই

স্টেট বাগগুলো প্রায়ই ব্যক্তিগত মনে হয়: UI “ভুল”, কিন্তু আপনি সহজতম প্রশ্নের উত্তর দিতে পারেন না—কে এই মান বদলে গেল এবং কখন? যদি একটি সংখ্যা উল্টে যায়, ব্যানার অদৃশ্য হয়, বা বোতাম নিজে ডিসেবল হয়ে যায়, তখন আপনাকে একটি টাইমলাইন দরকার, অনুমান নয়।

পরিবর্তনগুলো ট্রেসেবল করুন (রহস্যময় নয়)

সবচেয়ে দ্রুত পথে স্পষ্টতা আসে একটি পূর্বানুমেয় আপডেট ফ্লো থেকে। আপনি রিডিউসার, ইভেন্ট, বা একটি স্টোর ব্যবহার করুন—যখনই এমন প্যাটার্ন নিন যেখানে:

  • পরিবর্তনগুলো একটি ছোট সেট ভাল-নামক অ্যাকশনের মাধ্যমে ঘটে (যেতে না করে রেন্ডম মিউটেশন)
  • প্রতিটি অ্যাকশনের একটি পরিষ্কার পে-লোড থাকে (setShippingMethod('express'), updateStuff নয়)
  • আপনি অ্যাকশন ও রেজাল্টিং স্টেট ট্রানজিশন গুলো কনসিসটেন্টলি লগ করতে পারেন

সুস্পষ্ট অ্যাকশন লগিং ডিবাগিংকে “স্ক্রিনকে রাতারাতি তাকানো” থেকে “রশিদ অনুসরণ করা” তে পরিণত করে। সাধারণ কনসোল লগও (অ্যাকশন নাম + মূল ক্ষেত্র) সমস্যা পুনর্নির্মাণের চেয়ে দ্রুত কাজ করে।

স্থির জায়গায় লজিক টেস্ট করুন

প্রতিটি রি-রেন্ড টেস্ট করার চেষ্টা করবেন না। বরং সেই অংশগুলো টেস্ট করুন যেগুলো পিউর লজিকের মতো আচরণ করে:

  • ইউনিট টেস্ট রিডিউসার / স্টেট আপডেটার: পূর্ববর্তী স্টেট + অ্যাকশন দিলে পরবর্তী স্টেট পরীক্ষা করুন
  • ইউনিট টেস্ট সিলেক্টর / ডেরাইভড ক্যালকুলেশন: স্টেট দিলে কম্পিউটেড আউটপুটassert করুন
  • ইন্টিগ্রেশন টেস্ট মূল ইউজার ফ্লো: লগইন → ডেটা লোড → এডিট → সেভ → কনফার্মেশন দেখা

এই মিশ্রণটি “গণিত বাগ” এবং বাস্তব-বিশ্বের ওয়্যারিং সমস্যাও ধরবে।

অ্যাসিঙ্ক বাগের জন্য লাইটওয়েট ইনস্ট্রুমেন্টেশন যোগ করুন

অ্যাসিঙ্ক সমস্যা গ্যাপে লুকানো থাকে। টাইমলাইন দৃশ্যমান করার জন্য ন্যূনতম মেটাডেটা যোগ করুন:

  • গুরুত্বপূর্ণ আপডেটে টাইমস্ট্যাম্প
  • রিকোয়েস্ট আইডি (অ্যাকশন ও রেসপন্সে আইডি লাগান)

তখন যখন একটি দেরিতে আসা রেসপন্স নতুনটিকে ওভাররাইট করে, আপনি তা তৎক্ষণাৎ প্রমাণ করতে পারবেন—এবং আত্মবিশ্বাসের সাথে ঠিক করতে পারবেন।

একটা স্টেট ম্যানেজমেন্ট পন্থা বাছাই করা (টুল যুদ্ধে না নামে)

প্রোটোটাইপ স্টেট দ্রুত
চ্যাটেই একটি React অ্যাপ তৈরি করুন এবং প্রথম দিন থেকেই আপনার স্টেট মডেলকে সহজ রাখুন।

স্টেট টুল বাছাই করা সহজ হয় যখন আপনি এটাকে ডিজাইন সিদ্ধান্ত হিসেবে দেখেন, শুরুতে লাইব্রেরি নয়। লাইব্রেরি তুলনা করার আগে আপনার স্টেট সীমানাগুলো ম্যাপ করুন: কোনটা সম্পূর্ণ লোকাল, কোনটা শেয়ার করা প্রয়োজন, আর কোনটা আসলে সার্ভার ডেটা যা ফেচ ও সিঙ্ক করা দরকার।

প্রাসঙ্গিক নির্বাচনের মানদণ্ড

একটি ব্যবহারিক সিদ্ধান্ত নেওয়ার জন্য কয়েকটি সীমা দেখুন:

  • অ্যাপের আকার ও লাইফটাইম: ছোট ইন্টারনাল টুল সহজ থাকতে পারে; দীর্ঘমেয়াদি প্রোডাক্ট চুক্তি ও কনভেনশন উপকারে আনে
  • টিম অভ্যাস: এমন কিছু বাছুন যা আপনার দল ধারাবাহিকভাবে ব্যবহার করতে পারে (এবং কনফিগার করে রিভিউ করতে পারে)
  • অ্যাসিঙ্ক চাহিদা: ভারী ফেচিং, ক্যাশিং, পেজিনেশন, এবং মিউটেশনগুলো বিবেচনায় আনে
  • স্টেট জটিলতা: ক্রস-পেজ ওয়ার্কফ্লো, undo/redo, ও বহু ধাপের ফর্ম অতিরিক্ত স্ট্রাকচার প্রয়োজন পারে

তত্ত্ববিহীন উচ্চ-স্তরের তুলনা

  • Context + hooks: ডিপেনডেন্সি ইনজেকশন ও কম-ফ্রিকোয়েন্সি শেয়ার্ড ভ্যালুর জন্য চমৎকার (থিম, auth info)। স্টেটের জন্য কাজ করতে পারে, কিন্তু ফ্রিকুয়েন্ট আপডেটে অড-নয়েজ হতে পারে যদি অতিরিক্ত প্যাটার্ন না নেওয়া হয়।
  • Redux-স্টাইল স্টোর: শক্ত কনভেনশন, পূর্বানুমেয় আপডেট, এবং দুর্দান্ত টুলিং। জটিল ফিচারগুলোর জন্য ভাল যেখানে ক্লিয়ার অডিট ট্রেইল দরকার।
  • অ্যাটম-স্টোর (ফাইন-গ্রেইনড স্টেট): শেয়ার্ড স্টেট সহজে ব্যবহারের জন্য আর রিডিউসর ওয়্যারিং কম করে। ধীরে ধীরে স্কেল করা সহজ।
  • কুয়েরি ক্যাশ (সার্ভার-স্টেট টুল): ফেচিং, ক্যাশিং, ডিডুপিং, ব্যাকগ্রাউন্ড রিফেচিং, এবং মিউটেশনের জন্য বিশেষায়িত। অনেক অ্যাসিঙ্ক গ্লু কোড কমিয়ে দেয়।

টুল-প্রথম চিন্তা এড়িয়ে চলুন

“আমরা X ব্যাবহার করব” বলে শুরু করলে আপনি ভুল জায়গায় ভুল জিনিস স্টোর করবেন। অধিকার দিয়ে শুরু করুন: কে আপডেট করে, কে পড়ে, এবং বদলে গেলে কি হবে।

টুলগুলো মিশিয়ে ব্যবহার করাই প্রায়ই সবচেয়ে ভালো

অনেক অ্যাপ একটি সার্ভার-স্টেট লাইব্রেরি API ডেটার জন্য এবং একটি ছোট UI-স্টেট সমাধান কনটেক্সট/লোকাল স্টেটের জন্য ভালোভাবে করে। লক্ষ্য হল স্পষ্টতা: প্রতিটি স্টেট টাইপ সেই জায়গায় থাকুক যেখানে বোঝা সহজ।

Koder.ai কোথায় ফিট করে

যদি আপনি স্টেট সীমানা ও অ্যাসিঙ্ক ফ্লো নিয়ে দ্রুত পরীক্ষা-নিরীক্ষা করতে চান, Koder.ai আইডিয়া থেকে বাস্তবায়ন পর্যন্ত লুপ দ্রুত করে। এটি React ফ্রন্টএন্ড (এবং Go + PostgreSQL ব্যাকেন্ড) এজেন্ট-ভিত্তিক ওয়ার্কফ্লো থেকে জেনারেট করে, তাই আপনি লোকাল বনাম গ্লোবাল, সার্ভার ক্যাশ বনাম UI ড্রাফট ইত্যাদি আলাদা মালিকানা মডেল দ্রুত প্রোটোটাইপ করতে পারবেন এবং যেটা বেশি পূর্বানুমেয় সেটাই রেখে দিতে পারবেন।

দুটি ব্যবহারিক ফিচার উৎপাদন কালে সহায়ক: Planning Mode (বিল্ড করার আগে স্টেট মডেল আউটলাইন করতে) এবং snapshots + rollback (রিফ্যাক্টর—যেমন “ডেরাইভড স্টেট সরানো” বা “রিকোয়েস্ট আইডি চালু করা”—কর্ম সম্পাদনের সময় একটি কাজ করা ব্যাকআপ রাখা)।

স্টেট কম কষ্টদায়ক করার জন্য ব্যবহারিক চেকলিস্ট

স্টেট একটি ডিজাইন সমস্যা হিসেবে যখন দেখা হয়—কে মালিক, এটা কী প্রতিনিধিত্ব করে, এবং কিভাবে বদলে যায়—তখন এটি সহজ হয়। একটি কম্পোনেন্ট “রহস্যময়” লাগলে এই চেকলিস্ট ব্যবহার করুন।

1) মালিক এবং একক সত্য উৎস স্পষ্ট করুন

প্রশ্ন করুন: কোন অংশ অ্যাপের এই ডেটার জন্য দায়ী? স্টেট যেখানে প্রয়োজন সবচেয়ে কাছাকাছি রাখুন, এবং শুধুমাত্র যখন একাধিক অংশ প্রকৃতপক্ষে সমন্বয় করবে তখন লিফট করুন।

  • প্রতিটি স্টেটের জন্য এক মালিক।
  • ডেটা নিচে পাঠান; পরিবর্তনগুলো উপরে কলব্যাক/ইভেন্টের মাধ্যমে পাঠান।
  • যদি দুই জায়গা একই মান আপডেট করতে পারে, আপনার কাছে সত্যের একক উৎস নেই—একটি কনফ্লিক্ট অপেক্ষায় আছে।

2) অনুলিপি এড়ান এবং উৎপন্ন মান মডেল করুন

যদি আপনি অন্য স্টেট থেকে কিছু গণনা করতে পারেন, সেটি স্টোর করবেন না।

  • ন্যূনতম ইনপুট স্টোর করুন (উদাহরণ: items, filterText)।
  • আউটপুটগুলো রেন্ডার সময় বা মেমোইজেশন দিয়ে গণনা করুন (উদাহরণ: visibleItems)।

3) অ্যাসিঙ্ক স্টেট স্পষ্ট করুন (মীমাংসাহীন নয়)

অ্যাসিঙ্ক কাজ যখন স্পষ্টভাবে মডেল করা হয় তখন বুঝতে সহজ হয়:

  • একটি ছোট “রিকোয়েস্ট স্টেট” আকার পছন্দ করুন: status: 'idle' | 'loading' | 'success' | 'error', সাথে dataerror
  • “loading” ও “error” কে ফার্স্ট-ক্লাস UI স্টেট হিসেবে বিবেচনা করুন, একাধিক বুলিয়ান না ছড়িয়ে।

4) সাধারণ অ্যান্টি-প্যাটার্নগুলো খেয়াল রাখুন

  • প্রপসকে স্টেটে কপি করা “প্রয়োজন হলে” (ড্রিফট তৈরি করে)
  • সবকিছু গ্লোবাল করা (অপ্রয়োজনীয় কাপলিং আনে)
  • বুলিয়ান স্যুপ (isLoading, isFetching, isSaving, hasLoaded, …) – একটি স্ট্যাটাস স্ট্রিং ব্যবহার করুন।

5) ছোট, নিরাপদ ধাপে রিফ্যাক্টর করুন

  • মিশ্রিত স্টেট আলাদা করুন: UI কনসার্ন (ওপেন/ক্লোজ, ইনপুট টেক্সট) সার্ভার ডেটা থেকে আলাদা রাখুন।
  • স্টোর করা ডেরাইভড ভ্যালুগুলো মুছে ফেলুন এবং সেগুলো বাস্তব সোর্স থেকে গণনা করুন।
  • সাইড-ইফেক্ট (ফেচিং, সাবস্ক্রিপশন) ফিচারের প্রতি এক জায়গায় কেন্দ্রীভূত করুন।

ব্যবহারিক লক্ষ্য

কম “কেন এটা এই অবস্থায় আসে?” বাগ, পরিবর্তন করতে পাঁচটি ফাইল ছুঁতে না হওয়া, এবং এমন মানসিক মডেল যেখানে আপনি এক জায়গা পয়েন্ট করে বলতে পারেন: এখানেই সত্য আছে।

সাধারণ প্রশ্ন

ফ্রন্টএন্ড অ্যাপে স্টেট বলতে কী বোঝায়?

স্টেট হলো পরিবর্তনশীল ডেটা, যা ব্যবহারকারীরা কী দেখবেন তা নিয়ন্ত্রণ করে, যেমন ফর্মের মান, খোলা মডাল, নির্বাচিত ট্যাব বা কার্টের পণ্য। এটি বদলালে, এটি ব্যবহার করা সব জায়গায় UI-তে নতুন মানটি দেখা উচিত।

অ্যাপ বড় হওয়ার সঙ্গে সঙ্গে স্টেট ম্যানেজমেন্ট কেন কঠিন হয়ে যায়?

একই ডেটা বিভিন্ন স্ক্রিনে কাজে লাগাতে হলে, রিলোডের পরও রাখতে হলে বা API-এর সঙ্গে সিঙ্ক করতে হলে সমস্যা শুরু হয়। তখন ডেটা কোথায় থাকবে এবং কোন আপডেটটি প্রাধান্য পাবে, সে বিষয়ে স্পষ্ট নিয়ম দরকার।

সিঙ্গেল সোর্স অব ট্রুথ কী?

প্রতিটি তথ্যের একজন মালিক রাখুন। অন্য কম্পোনেন্টগুলোর নিজেদের সম্পাদনাযোগ্য কপি রাখার বদলে সেই ডেটার গণনাকৃত বা সিঙ্ক্রোনাইজ করা ভিউ পড়া উচিত।

গ্লোবাল স্টেটের বদলে কখন লোকাল স্টেট ব্যবহার করা উচিত?

যে কম্পোনেন্ট বা পেজ এটি ব্যবহার করে, তার কাছেই UI স্টেট রাখুন। কাছাকাছি অংশগুলোকে সমন্বয় করতে হলে এটি একটি শেয়ার করা প্যারেন্টে নিন, আর অনেক দূরের অংশে সত্যিই একই তথ্য দরকার হলেই কেবল গ্লোবাল স্টেট ব্যবহার করুন।

UI স্টেট এবং সার্ভার স্টেটের মধ্যে পার্থক্য কী?

UI স্টেট বর্তমান ইন্টারঅ্যাকশন বোঝায়, যেমন খোলা ডায়ালগ, সক্রিয় ট্যাব বা সংরক্ষণ না করা সার্চ টেক্সট। সার্ভার স্টেট API থেকে আসে এবং এর জন্য ফেচিং, ক্যাশিং, ত্রুটি সামলানো ও রিফ্রেশের নিয়ম দরকার।

কার্টের মোটের মতো ডেরাইভড মান কি স্টেটে রাখা উচিত?

সাধারণত না। কার্টের মোট, ফিল্টার করা তালিকা এবং ভ্যালিডেশন ফলাফল তাদের ইনপুট থেকে হিসাব করুন, যাতে সেগুলো সিঙ্কের বাইরে না যায়। প্রকৃত পারফরম্যান্স খরচ শনাক্ত করার পরেই কেবল কোনো হিসাব ক্যাশ করুন।

লোডিং ও ত্রুটি স্টেট কীভাবে ম্যানেজ করা উচিত?

রিকোয়েস্টকে সরাসরি idle, loading, success বা error-এর মতো একটি স্ট্যাটাস দিয়ে মডেল করুন, সঙ্গে তার ডেটা ও ত্রুটিও রাখুন। এতে রিকোয়েস্টের প্রতিটি পর্যায়ে UI রেন্ডার করার জন্য একটি স্পষ্ট স্টেট পায়।

পুরোনো API রেসপন্স যেন নতুন ডেটা ওভাররাইট না করে, তা কীভাবে আটকাব?

সম্ভব হলে পুরোনো রিকোয়েস্ট বাতিল করুন, অথবা একটি রিকোয়েস্ট ID যোগ করে কেবল তখনই রেসপন্স গ্রহণ করুন, যখন সেটি সর্বশেষ রিকোয়েস্টের সঙ্গে মেলে। এতে পুরোনো, ধীর রেসপন্স নতুন ফলাফলকে প্রতিস্থাপন করতে পারে না।

ছোট একটি স্টেট আপডেটেও আমার UI ধীর হয়ে যেতে পারে কেন?

সম্পর্কহীন স্টেটকে ছোট ছোট অংশে ভাগ করুন এবং অপ্রয়োজনে বড় অবজেক্ট বা অ্যারে নতুন করে তৈরি করা এড়িয়ে চলুন। ব্যয়বহুল ফিল্টার করা বা রূপান্তরিত ডেটা কেবল তার আসল ইনপুট বদলালেই হিসাব করুন, বিশেষ করে বড় তালিকার ক্ষেত্রে।

স্টেট ম্যানেজমেন্ট টুল কীভাবে বেছে নেব?

মালিকানা ও ডেটার ধরন চিহ্নিত করার পর টুল বেছে নিন। API ডেটার জন্য কোয়েরি ক্যাশ, কম্পোনেন্ট ইন্টারঅ্যাকশনের জন্য লোকাল স্টেট, আর বহু ফিচারের সমন্বিত ক্লায়েন্ট-সাইড আপডেট দরকার হলে স্টোর উপযোগী।

Related posts