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

একটি ফ্রন্টএন্ড অ্যাপে স্টেট হলো সহজভাবে ওই ডেটা যার ওপর আপনার UI নির্ভর করে এবং যেটি সময়ের সাথে বদলে যেতে পারে।
স্টেট বদলালে স্ক্রিনও মিলিয়ে আপডেট হওয়া উচিত। যদি স্ক্রিন আপডেট না হয়, অনিয়মিতভাবে আপডেট হয়, বা পুরোনো ও নতুন মানের মিশ্রণ দেখায়, তখনই আপনি “স্টেট সমস্যা” অনুভব করবেন — বোতামগুলো ডিসেবলেড থেকে যায়, মোটগুলো মেলে না, বা ভিউটি ব্যবহারকারীর সাম্প্রতিক কাজ প্রতিফলিত করে না।
স্টেট ছোট ও বড় দুটো ইন্টারঅ্যাকশনে উভয়েই আসে, যেমন:
এইগুলোর কিছু “অস্থায়ী” (যেমন একটি নির্বাচিত ট্যাব), আবার কিছু “গুরুত্বপূর্ণ” (যেমন কার্ট)। এগুলো সবই স্টেট কারণ এগুলোই নির্ধারণ করে UI এখন কী রেন্ডার করবে।
একটি সাধারণ ভেরিয়েবল শুধু যেখানে থাকে সেই জায়গায়ই প্রাসঙ্গিক। স্টেট আলাদা কারণ এটির কিছু নিয়ম আছে:
স্টেট ম্যানেজমেন্টের আসল লক্ষ্য ডেটা সংরক্ষণ করা নয়—এটি আপডেটগুলোকে পূর্বানুমেয় করা যাতে UI সামঞ্জস্যপূর্ণ থাকে। যখন আপনি উত্তর দিতে পারেন “কি বদলেছে, কখন, এবং কেন,” তখন স্টেট নিয়ন্ত্রণযোগ্য হয়। যখন পারেন না, তখন সাধারণ ফিচারগুলোও আশ্চর্যের কারণ হয়ে দাঁড়ায়।
প্রকল্প শুরুতে স্টেট প্রায় নীরসভাবে সহজ লাগে—ভালো অর্থে। আপনার একটি কম্পোনেন্ট, একটি ইনপুট, এবং একটি স্পষ্ট আপডেট আছে। ব্যবহারকারী একটি ফিল্ডে টাইপ করে, আপনি সেই মান সেভ করেন, UI রি-রেন্ডার করে। সবকিছু দৃশ্যমান, অবিলম্বে, এবং সীমাবদ্ধ।
একটি টেক্সট ইনপুট কল্পনা করুন যা আপনি টাইপ করলে তার প্রিভিউ দেখায়:
এই সেটআপে স্টেট মূলত: একটি ভেরিয়েবল যা সময়ের সাথে বদলায়। আপনি বলতে পারবেন কোথায় রাখা আছে এবং কোথায় আপডেট হচ্ছে, আর হলেন।
লোকাল স্টেট কাজ করে কারণ মানসিক মডেল কোড স্ট্রাকচারের সাথে মিলে যায়:
এমনকি যদি আপনি React-এর মতো ফ্রেমওয়ার্ক ব্যবহার করেন, আর্কিটেকচারের ব্যাপারে গভীরভাবে ভাবতে হয় না। ডিফল্টগুলো যথেষ্ট।
জবারই অ্যাপ “একটি উইজেটের পেজ” থেকে “একটি প্রোডাক্ট” হয়ে ওঠে, স্টেট আর এক জায়গায় থাকে না।
একই ডেটা এখন বিভিন্ন জায়গায় লাগতে পারে:
একটি প্রোফাইল নাম হেডারে দেখানো হতে পারে, সেটিংসে এডিট করা হতে পারে, দ্রুত লোড করার জন্য ক্যাশ করা হতে পারে, এবং ওয়েলকাম মেসেজ পার্সোনালাইজ করতে ব্যবহার হতে পারে। হঠাৎ করে প্রশ্ন হয় কীভাবে রাখলে সব জায়গায় সঠিক থাকবে।
স্টেট জটিলতা ধীরে বেড়ে না—এটি একপ্রকার লাফ দেয়।
একই ডেটা পড়ার আরেকটা জায়গা যোগ করলেই এটা “দুই গুণ কঠিন” হয় না। এটি সমন্বয় সমস্যা নিয়ে আসে: ভিউগুলিকে কনসিস্টেন্ট রাখা, স্টেইল মান প্রতিরোধ করা, কে কি আপডেট করবে সিদ্ধান্ত নেওয়া, এবং টাইমিং হ্যান্ডল করা। কয়েকটি শেয়ার করা স্টেট ও অ্যাসিঙ্ক কাজ থাকলেই আচরণ বোঝা কঠিন হয়ে যেতে পারে—যদিও প্রতিটি ফিচার নিজেই সাধারণই লাগছে।
একই “তথ্য” একাধিক জায়গায় রাখা হলে স্টেট কষ্টদায়ক হয়ে যায়। প্রতিটি কপি় বিচ্যুত হতে পারে, এবং এখন আপনার UI নিজে থেকেই বিরোধ শুরু করে।
বহু অ্যাপেই সাধারণত কয়েকটি জায়গা থাকে যেখানে “তথ্য” থাকতে পারে:
এসবের প্রতিটিই কোনো না কোনো স্টেটের জন্য বৈধ মালিক হতে পারে। সমস্যা শুরু হয় যখন সবগুলোই একই স্টেটকে নিজেদের মালিক বানাতে চায়।
একটি সাধারণ প্যাটার্ন: সার্ভার থেকে ডেটা ফেচ করে সেটিকে লোকাল স্টেটে কপি করা “তাই যে আমরা এডিট করতে পারি”। উদাহরণ: আপনি ইউজার প্রোফাইল লোড করে formState = userFromApi সেট করেন। পরে সার্ভার রিফেচ করে (অথবা আরেকটি ট্যাব রেকর্ড আপডেট করে), তখন আপনার কাছে দুইটি ভেরিয়েন্ট থাকে: ক্যাশ একটি বলে আর আপনার ফর্ম আরেকটি।
ডুপ্লিকেশন “সহায়ক” ট্রান্সফর্মেশনের মাধ্যমে ও ঘসে পড়ে: items এবং itemsCount একসঙ্গে রাখা, বা selectedId এবং selectedItem একই কারণে রাখা।
একাধিক সত্য উৎস থাকলে বাগগুলোর সাধারণ কণ্ঠ হয়:
প্রতিটি স্টেটের জন্য একটি মালিক পয়েন্ট করুন—যেখানে আপডেট করা হয়—এবং বাকিদেরকে প্রজেকশন হিসেবে বিবেচনা করুন (রিড-ওনলি, ড্যারাইভড, বা একদিকে-সিঙ্ক)। আপনি যদি মালিককে পয়েন্ট করতে না পারেন, তাহলে সম্ভবত একই সত্য আপনি দুবারই স্টোর করছেন।
অনেক ফ্রন্টএন্ড স্টেট সহজ লাগে কারণ তা সিঙ্ক্রোনাস: ব্যবহারকারী ক্লিক করে, আপনি মান সেট করেন, UI আপডেট করে। সাইড-ইফেক্ট সেই ধারাবাহিক গল্প ভাঙে।
সাইড-ইফেক্ট হলো যেকোনো অ্যাকশন যা আপনার কম্পোনেন্টের পিউর “ডেটার ওপর রেন্ডার” মডেলের বাইরে যায়:
প্রতিটি কখনোও পরে ফায়ার হতে পারে, অকল্পনীয়ভাবে ব্যর্থ হতে পারে, বা বারবার চালাতে পারে।
অ্যাসিঙ্ক আপডেটগুলো সময়কে একটি ভ্যারিয়েবল হিসেবে পরিণত করে। আপনি আর “কি ঘটেছে” নিয়ে চিন্তা করেন না, বরং “কি সম্ভবত এখনো ঘটছে” নিয়ে চিন্তা করেন। দুটি রিকোয়েস্ট overlap করতে পারে। একটি ধীর রেসপন্স নতুনটির পরে আসতে পারে। একটি কম্পোনেন্ট আনমাউন্ট হওয়ার সময়ও একটি অ্যাসিঙ্ক কল স্টেট আপডেট করতে পারে।
এই কারণে বাগগুলো সাধারণত এরকম দেখায়:
বিভিন্ন জায়গায় isLoading মতো বুলিয়ান ছড়িয়ে দেওয়ার বদলে অ্যাসিঙ্ক কাজকে একটি ছোট স্টেট মেশিন হিসেবে বিবেচনা করুন:
ডেটা এবং স্ট্যাটাস একসাথে ট্র্যাক করুন, এবং একটি আইডেন্টিফায়ার (রিকোয়েস্ট আইডি বা কুয়েরি কী) রাখুন যাতে আপনি দেরিতে আসা রেসপন্সগুলো উপেক্ষা করতে পারেন। এভাবে “এখন UI কী দেখাবে?” প্রশ্নটি সম্ভাব্যতার বদলে একটি সরল সিদ্ধান্ত হবে।
অনেক স্টেট সমস্যা একটি সহজ মিশআপ থেকেই শুরু: “যে মুহূর্তে UI কী করছে” কে “যে সার্ভার বলে সত্য” এর সাথেই মিলিয়ে ফেলা। উভয়ই সময়ের সাথে বদলে যেতে পারে, কিন্তু তাদের নিয়ম আলাদা।
UI স্টেট অস্থায়ী এবং ইন্টারঅ্যাকশন চালিত। এটি সেই মুহূর্তে স্ক্রিনকে ব্যবহারকারীর প্রত্যাশা অনুযায়ী রেন্ডার করার জন্য থাকে।
উদাহরণ: মডাল ওপেন/ক্লোজ, একটিভ ফিল্টার, সার্চ ইনপুট ড্রাফট, হোভার/ফোকাস, কোন ট্যাব নির্বাচিত, পেজিনেশন UI (কারেন্ট পেজ, পেজ সাইজ, স্ক্রল পজিশন)।
এই স্টেট সাধারণত পেজ বা কম্পোনেন্ট ট্রির লোকাল। নেভিগেট করলে রিসেট হওয়াও ঠিক আছে।
সার্ভার স্টেট হলো API থেকে আসা ডেটা: ইউজার প্রোফাইল, প্রোডাক্ট লিস্ট, পারমিশন, নোটিফিকেশন, সেভ করা সেটিংস। এটা “রিমোট ট্রুথ” যা আপনার UI কিছু না করলেই বদলে যেতে পারে (কেউ অন্যজন এটাকে এডিট করে, সার্ভার এটা পুনরপরিগণনা করে, ব্যাকগ্রাউন্ড জব আপডেট করে)।
কারণ এটি রিমোট, তাই এটাকে লোডিং/এরর স্টেট, ক্যাশ টাইমস্ট্যাম্প, রিট্রাই, এবং ইনভ্যালিডেশন মতো মেটাডেটাও দরকার।
যদি আপনি UI ড্রাফটকে সার্ভার ডেটার ভিতরে স্টোর করেন, একটি রিফেচ লোকাল এডিট মুছে দিতে পারে। যদি আপনি সার্ভার রেসপন্সকে UI স্টেটে স্টোর করেন কিন্তু কোনো ক্যাশ নিয়ম না রাখেন, আপনি স্টেইল ডেটা, ডুপ্লিকেট ফেচ, এবং অসামঞ্জস্যপূর্ণ স্ক্রিন পাবেন।
একটি সাধারণ ব্যর্থ মোড: ব্যবহারকারী একটি ফর্ম এডিট করছে, তখন ব্যাকগ্রাউন্ড রিফেচ শেষ হয় এবং ইনকামিং রেসপন্স ড্রাফটকে ওভাররাইট করে ফেলে।
সার্ভার স্টেটকে ক্যাশিং প্যাটার্ন দিয়ে ম্যানেজ করুন (ফেচ, ক্যাশ, ইনভেলিডেট, ফোকাসে রিফেচ) এবং এটাকে শেয়ার্ড ও অ্যাসিঙ্ক্রোনাস হিসেবে বিবেচনা করুন।
UI স্টেটকে লোকাল টুল দিয়ে ম্যানেজ করুন (লোকাল কম্পোনেন্ট স্টেট, কনটেক্সট যখন সত্যিই শেয়ার করা UI কনসার্ন থাকে), এবং ড্রাফটগুলো আলাদা রাখুন যতক্ষণ না আপনি ইচ্ছাকৃতভাবে সেগুলো সার্ভারে “সেভ” করছেন।
উৎপন্ন স্টেট হলো এমন কোন মান যা অন্য স্টেট থেকে গণনা করা যায়: কার্টের মোট লাইন আইটেম থেকে, ফিল্টার করা লিস্ট মূল লিস্ট + সার্চ কুয়েরি থেকে, কিংবা 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, সিলেক্টর মেমোইজেশন) ব্যবহার করুন যাতে ক্যাশ কীগুলো সঠিক ইনপুটগুলোর উপর ভিত্তি করে থাকে—নাহলে আপনি আবার ড্রিফট নিয়ে ফিরবেন, কেবল পারফরম্যান্সের ঝাঁপ তুলে।
স্টেট কষ্টদায়ক হয় যখন এটা অস্পষ্ট হয়ে যায় কে অধিকারী।
কোনো স্টেটের অধিকারী হল সেই জায়গা যেখানে স্টেট আপডেট করার অধিকার আছে। অন্য অংশগুলো সেটি পড়তে পারে (প্রপস, কনটেক্সট, সিলেক্টর ইত্যাদি মারফত), কিন্তু সরাসরি বদলানো উচিত নয়।
স্পষ্ট অধিকার দুইটি প্রশ্নের উত্তর দেয়:
যখন এসব সীমানা ধূসর হয়, আপনি কনফ্লিক্টেড আপডেট, “টা কেন বদললো?” মুহূর্ত, এবং রিইউজ করা কঠিন কম্পোনেন্ট পান।
স্টেট গ্লোবাল স্টোর বা টপ-লেভেল কনটেক্সটে রাখা পরিষ্কার মনে হতে পারে: যেকোনো জিনিস এটি অ্যাক্সেস করতে পারে, প্রপ ড্রিল দূর হয়। ট্রেডঅফ হলো অনিচ্ছাকৃত কাপলিং—হঠাৎ করে সম্পর্কহীন স্ক্রিনগুলো একই ভ্যালুর উপর নির্ভর করতে শুরু করে, এবং ছোট পরিবর্তনও পুরো অ্যাপ জুড়ে ঢেউ তুলতে পারে।
গ্লোবাল স্টেট উপযুক্ত যেখানে সত্যিই ক্রস-কাটিং কনসার্ন আছে, যেমন কারেন্ট ইউজার সেশন, অ্যাপ-ওয়াইড ফিচার ফ্ল্যাগ, বা শেয়ার্ড নোটিফিকেশন কিউ।
একটি সাধারণ প্যাটার্ন: লোকাল থেকে শুরু করে সেই নিকটতম কমন পেরেন্ট পর্যন্ত স্টেট লিফট করুন যখন দুটো সাইব্লিং অংশে সমন্বয় প্রয়োজন।
যদি কেবল একটি কম্পোনেন্টের প্রয়োজন থাকে, সেখানে রাখুন। যদি একাধিক কম্পোনেন্টের প্রয়োজন হয়, সবচেয়ে ছোট শেয়ারড মালিক পর্যন্ত লিফট করুন। যদি বহু দূরবর্তী এলাকায় দরকার হয়, তখনই গ্লোবাল বিবেচনা করুন।
স্টেট যেখানে ব্যবহার হয় সেখানে যত কাছাকাছি রাখুন যতক্ষণ না শেয়ারিং প্রয়োজন।
এটি কম্পোনেন্টগুলিকে বোঝা সহজ রাখে, অনিচ্ছাকৃত ডিপেনডেন্সি কমায়, এবং ভবিষ্যতের রেফ্যাক্টরিং কম ভয়ানক করে কারণ কম ফাইলেই পরিবর্তন লাগে।
ফ্রন্টএন্ড অ্যাপগুলো “সিঙ্গল-থ্রেডেড” মনে হলেও ব্যবহারকারী ইনপুট, টাইমার, অ্যানিমেশন, এবং নেটওয়ার্ক সবই স্বাধীনভাবে চলে। এর মানে একাধিক আপডেট একই সময়ে চলতে পারে—এবং এগুলো যে ক্রমে শুরু হয় ঠিক সেই ক্রমে শেষ না-ও হতে পারে।
একটি সাধারণ সংঘর্ষ: UI-এর দুটি অংশ একই স্টেট আপডেট করে।
query আপডেট করে।query (অথবা একই রেজাল্ট লিস্ট) আপডেট করে।প্রত্যেকে আলাদাভাবে সঠিক, কিন্তু একসাথে তারা টাইমিং অনুসারে একে অপরকে ওভাররাইট করে দিতে পারে। এমনকি খারাপ হলে আপনি নতুন ফিল্টার দেখাচ্ছেন অথচ রেজাল্ট হচ্ছে আগের কুয়েরির জন্য।
রেস কন্ডিশন তখনই দেখা দেয় যখন আপনি রিকোয়েস্ট A চালান, তারপর দ্রুত রিকোয়েস্ট B চালান—কিন্তু রিকোয়েস্ট A পরে ফিরে আসে।
উদাহরণ: ব্যবহারকারী টাইপ করে “c”, “ca”, “cat”。 যদি “c” রিকোয়েস্ট ধীর হয় এবং “cat” দ্রুত হয়, UI প্রথমে “cat” ফল দেখাতে পারে এবং পরে স্টেইল “c” ফল দ্বারা ওভাররাইট হয়ে যেতে পারে।
বাগ সূক্ষ্ম কারণ সবকিছু “কার্যকর” ছিল—শুধু ভুল ক্রমে।
সাধারণত নিচের কোন একটি কৌশল প্রয়োগ করতে চান:
AbortController)।একটি সরল রিকোয়েস্ট আইডি পদ্ধতি:
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 “ভুল”, কিন্তু আপনি সহজতম প্রশ্নের উত্তর দিতে পারেন না—কে এই মান বদলে গেল এবং কখন? যদি একটি সংখ্যা উল্টে যায়, ব্যানার অদৃশ্য হয়, বা বোতাম নিজে ডিসেবল হয়ে যায়, তখন আপনাকে একটি টাইমলাইন দরকার, অনুমান নয়।
সবচেয়ে দ্রুত পথে স্পষ্টতা আসে একটি পূর্বানুমেয় আপডেট ফ্লো থেকে। আপনি রিডিউসার, ইভেন্ট, বা একটি স্টোর ব্যবহার করুন—যখনই এমন প্যাটার্ন নিন যেখানে:
setShippingMethod('express'), updateStuff নয়)সুস্পষ্ট অ্যাকশন লগিং ডিবাগিংকে “স্ক্রিনকে রাতারাতি তাকানো” থেকে “রশিদ অনুসরণ করা” তে পরিণত করে। সাধারণ কনসোল লগও (অ্যাকশন নাম + মূল ক্ষেত্র) সমস্যা পুনর্নির্মাণের চেয়ে দ্রুত কাজ করে।
প্রতিটি রি-রেন্ড টেস্ট করার চেষ্টা করবেন না। বরং সেই অংশগুলো টেস্ট করুন যেগুলো পিউর লজিকের মতো আচরণ করে:
এই মিশ্রণটি “গণিত বাগ” এবং বাস্তব-বিশ্বের ওয়্যারিং সমস্যাও ধরবে।
অ্যাসিঙ্ক সমস্যা গ্যাপে লুকানো থাকে। টাইমলাইন দৃশ্যমান করার জন্য ন্যূনতম মেটাডেটা যোগ করুন:
তখন যখন একটি দেরিতে আসা রেসপন্স নতুনটিকে ওভাররাইট করে, আপনি তা তৎক্ষণাৎ প্রমাণ করতে পারবেন—এবং আত্মবিশ্বাসের সাথে ঠিক করতে পারবেন।
স্টেট টুল বাছাই করা সহজ হয় যখন আপনি এটাকে ডিজাইন সিদ্ধান্ত হিসেবে দেখেন, শুরুতে লাইব্রেরি নয়। লাইব্রেরি তুলনা করার আগে আপনার স্টেট সীমানাগুলো ম্যাপ করুন: কোনটা সম্পূর্ণ লোকাল, কোনটা শেয়ার করা প্রয়োজন, আর কোনটা আসলে সার্ভার ডেটা যা ফেচ ও সিঙ্ক করা দরকার।
একটি ব্যবহারিক সিদ্ধান্ত নেওয়ার জন্য কয়েকটি সীমা দেখুন:
“আমরা X ব্যাবহার করব” বলে শুরু করলে আপনি ভুল জায়গায় ভুল জিনিস স্টোর করবেন। অধিকার দিয়ে শুরু করুন: কে আপডেট করে, কে পড়ে, এবং বদলে গেলে কি হবে।
অনেক অ্যাপ একটি সার্ভার-স্টেট লাইব্রেরি API ডেটার জন্য এবং একটি ছোট UI-স্টেট সমাধান কনটেক্সট/লোকাল স্টেটের জন্য ভালোভাবে করে। লক্ষ্য হল স্পষ্টতা: প্রতিটি স্টেট টাইপ সেই জায়গায় থাকুক যেখানে বোঝা সহজ।
যদি আপনি স্টেট সীমানা ও অ্যাসিঙ্ক ফ্লো নিয়ে দ্রুত পরীক্ষা-নিরীক্ষা করতে চান, Koder.ai আইডিয়া থেকে বাস্তবায়ন পর্যন্ত লুপ দ্রুত করে। এটি React ফ্রন্টএন্ড (এবং Go + PostgreSQL ব্যাকেন্ড) এজেন্ট-ভিত্তিক ওয়ার্কফ্লো থেকে জেনারেট করে, তাই আপনি লোকাল বনাম গ্লোবাল, সার্ভার ক্যাশ বনাম UI ড্রাফট ইত্যাদি আলাদা মালিকানা মডেল দ্রুত প্রোটোটাইপ করতে পারবেন এবং যেটা বেশি পূর্বানুমেয় সেটাই রেখে দিতে পারবেন।
দুটি ব্যবহারিক ফিচার উৎপাদন কালে সহায়ক: Planning Mode (বিল্ড করার আগে স্টেট মডেল আউটলাইন করতে) এবং snapshots + rollback (রিফ্যাক্টর—যেমন “ডেরাইভড স্টেট সরানো” বা “রিকোয়েস্ট আইডি চালু করা”—কর্ম সম্পাদনের সময় একটি কাজ করা ব্যাকআপ রাখা)।
স্টেট একটি ডিজাইন সমস্যা হিসেবে যখন দেখা হয়—কে মালিক, এটা কী প্রতিনিধিত্ব করে, এবং কিভাবে বদলে যায়—তখন এটি সহজ হয়। একটি কম্পোনেন্ট “রহস্যময়” লাগলে এই চেকলিস্ট ব্যবহার করুন।
প্রশ্ন করুন: কোন অংশ অ্যাপের এই ডেটার জন্য দায়ী? স্টেট যেখানে প্রয়োজন সবচেয়ে কাছাকাছি রাখুন, এবং শুধুমাত্র যখন একাধিক অংশ প্রকৃতপক্ষে সমন্বয় করবে তখন লিফট করুন।
যদি আপনি অন্য স্টেট থেকে কিছু গণনা করতে পারেন, সেটি স্টোর করবেন না।
items, filterText)।visibleItems)।অ্যাসিঙ্ক কাজ যখন স্পষ্টভাবে মডেল করা হয় তখন বুঝতে সহজ হয়:
status: 'idle' | 'loading' | 'success' | 'error', সাথে data ও error।isLoading, isFetching, isSaving, hasLoaded, …) – একটি স্ট্যাটাস স্ট্রিং ব্যবহার করুন।কম “কেন এটা এই অবস্থায় আসে?” বাগ, পরিবর্তন করতে পাঁচটি ফাইল ছুঁতে না হওয়া, এবং এমন মানসিক মডেল যেখানে আপনি এক জায়গা পয়েন্ট করে বলতে পারেন: এখানেই সত্য আছে।