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

প্রথমে React হতাশাজনক মনে হতে পারে কারণ আপনি UI-তে পরিবর্তন দেখেন, কিন্তু সবসময় বোঝাতে পারেন না কেন সেটা হল। আপনি কোনো বাটনে ক্লিক করেন, কিছু আপডেট হয়, এবং পেজের অন্য কোনো অংশ আপনাকে চমকে দেয়। সাধারণত এটি “React অদ্ভুত” নয়। এটি হচ্ছে “React কী করছে তার আমার ধারণা ঝাপসা।”
মানসিক মডেল হলো আপনি নিজের কাছে কোন কিছু কীভাবে কাজ করে তার সহজ গল্প। যদি গল্পটা ভুল হয়, আপনি আত্মবিশ্বাসী সিদ্ধান্ত নেবেন যা বিভ্রান্তিকর ফল দেয়। থার্মোস্ট্যাটটা ভাবুন: খারাপ মডেল হচ্ছে “আমি 22°C সেট করলাম, তাই ঘর একেবারে তৎক্ষণাৎ 22°C হয়ে যাবে।” একটা ভালো মডেল হচ্ছে “আমি একটা লক্ষ্য সেট করি, এবং হিটার সময়ের সাথে চালু/বন্ধ হয়ে সেই লক্ষ্য পৌঁছে দেয়।” ভালো গল্প থাকলে আচরণটা র্যান্ডম লাগতে বন্ধ করে।
React-ও একই রকম। কয়েকটি পরিষ্কার ধারণা গ্রহণ করলে React পূর্বানুমেয় হয়ে যায়: আপনি বর্তমান ডেটা দেখে নির্ভরযোগ্যভাবে আন্দাজ করতে পারবেন কী স্ক্রিনে থাকবে।
Dan Abramov এই “এটাকে পূর্বানুমেয় করো” মানসিকতাকে জনপ্রিয় করেছেন। লক্ষ্য নিয়ম মুখস্থ করা নয়। এটা হলো আপনার মাথায় কয়েকটা সত্য রাখা যাতে আপনি ট্রায়াল-এন্ড-এরর করে নয়, যুক্তি করে ডিবাগ করতে পারেন।
এই ধারণাগুলো মনে রাখুন:
এইগুলো ধরে রাখলে React জাদু লাগা বন্ধ হয়ে যাবে। এটা একটা সিস্টেম মনে হবে যাতে আপনি বিশ্বাস রাখতে পারেন।
React সহজ হয়ে যায় যখন আপনি “স্ক্রীন” চিন্তা করা বন্ধ করে ছোট টুকরোতে ভাবা শুরু করবেন। একটি কম্পোনেন্ট হলো UI-এর পুনরায় ব্যবহারযোগ্য ইউনিট। এটি ইনপুট নেয় এবং সেসব ইনপুটের জন্য UI কেমন হওয়া উচিত তার বিবরণ রিটার্ন করে।
একটি কম্পোনেন্টকে একটি পিউর বর্ণনা হিসেবে দেখা সাহায্য করে: “এই ডেটা দেওয়া হলে, এটা দেখাও।” এই বর্ণনাটি বহু জায়গায় ব্যবহার করা যাবে কারণ এটি তার অবস্থানের উপর নির্ভর করে না।
Props হলো ইনপুট। এগুলো একটি প্যারেন্ট কম্পোনেন্ট থেকে আসে। Props কোনো কম্পোনেন্টের “মালিকানাধীন” নয়, এবং কম্পোনেন্টকে এগুলো নীরবে পরিবর্তন করা উচিত নয়। যদি একটি বাটন label="Save" পায়, বাটনের কাজ হলো সেই লেবেল রেন্ডার করা, সিদ্ধান্ত নেওয়া নয় যে এটা আলাদা হওয়া উচিত।
State হলো মালিকানাধীন ডেটা। এটি হলো যা কম্পোনেন্ট সময়ের সাথে মনে রাখে। State তখন বদলে যায় যখন ব্যবহারকারী ইন্টারঅ্যাক্ট করে, কোনো রিকোয়েস্ট শেষ হয়, বা আপনি সিদ্ধান্ত নেন কিছু আলাদা হওয়া উচিত। Props থেকে ভিন্ন, state ওই কম্পোনেন্টের (অথবা যাকে আপনি মালিক বানান তার) হয়।
মূল আইডিয়াটির সরল ভাষ্য: UI হলো state-র একটি ফাংশন। যদি state বলে “loading”, একটি spinner দেখাও। যদি state বলে “error”, একটি মেসেজ দেখাও। যদি state বলে “items = 3”, তিনটি সারি রেন্ডার করো। আপনার কাজ হলো UI-কে state থেকে পড়তে রাখা, হিডেন ভ্যারিয়েবলের দিকে না ভেঙ্গে পড়া।
ধারণাগুলো আলাদা করে ধরার দ্রুত উপায়:
SearchBox, ProfileCard, CheckoutForm)name, price, disabled)isOpen, query, selectedId)উদাহরণ: একটি modal। প্যারেন্ট title এবং onClose props হিসাবে পাঠাতে পারে। modal isAnimating স্টেট মালিকানায় রাখতে পারে।
আপনি যদি চ্যাটের মাধ্যমে UI জেনারেটও করেন (উদাহরণস্বরূপ Koder.ai-তে), এই পৃথকীকরণই দ্রুততম উপায় বজায় রাখার জন্য: প্রথমে ঠিক করুন কি props এবং কি state, তারপর UI অনুসরণ করুক।
React মাথায় রাখার উপকারী উপায় (Dan Abramov-র ভাবনাকে মনে করিয়ে দেয়) হলো: rendering হল একটি গণনা, পেইন্ট জব নয়। React আপনার কম্পোনেন্ট ফাংশনগুলো চালায় বর্তমান props এবং state-র জন্য UI কেমন হওয়া উচিত তা নির্নয় করার জন্য। আউটপুট হলো UI বর্ণনা, পিক্সেল নয়।
একটি re-render মানে React কেবল সেই গণনাটি আবার করে। এর মানে “পুরো পেজ আবার আঁকা হচ্ছে” নয়। React নতুন রেজাল্টকে পূর্বের সাথে তুলনা করে এবং সত্য DOM-এ সবচেয়ে খাটো পরিবর্তনগুলো প্রয়োগ করে। অনেক কম্পোনেন্ট re-render হতে পারে যখন কেবল কয়েকটি DOM নোডই আপডেট হয়।
বেশি re-render কয়েকটি সহজ কারণে হয়: একটি কম্পোনেন্টের state বদলেছে, তার props বদলেছে, অথবা একটি প্যারেন্ট re-render করেছে এবং React child-কে আবার render করতে বলেছে। শেষটি মানুষকে চমকে দেয়, কিন্তু সাধারণত ঠিক আছে। যদি আপনি render-কে “cheap and boring”ভাবে ধরেন, আপনার অ্যাপটি যুক্তি করা সহজ থাকে।
এটি পরিষ্কার রাখার নিয়ম: render কে পিউর রাখুন। একই ইনপুট (props + state) দিলে আপনার কম্পোনেন্ট একই UI বর্ণনা রিটার্ন করা উচিত। render থেকে সারপ্রাইজগুলো দূরে রাখুন।
কনক্রিট উদাহরণ: যদি আপনি render-এ Math.random() দিয়ে একটি ID জেনারেট করেন, একটি re-render এটা বদলে ফেলবে এবং হঠাৎ একটি checkbox ফোকাস হারাতে পারে বা একটি লিস্ট আইটেম remount হতে পারে। ID একবারই তৈরি করুন (state, memo, বা কম্পোনেন্টের বাইরে) এবং render স্থিতিশীল হয়ে যাবে।
একটি বাক্য মনে রাখুন: re-render মানে “UI কী হওয়া উচিত তা পুনরায় গণনা করা,” পুরো কিছু পুনরায় বানানো নয়।
আরেকটি সহায়ক মডেল: state আপডেটগুলো অনুরোধ, তাত্ক্ষণিক অ্যাসাইনমেন্ট নয়। যখন আপনি setCount(count + 1) কল করেন, আপনি React-কে একটি নতুন মান দিয়ে রেন্ডার শিডিউল করতে বলছেন। আপনি যদি পরক্ষণেই state পড়েন, তখনও আপনি পুরানো মানই দেখতে পারেন কারণ React এখনও render করেনি।
এই কারণেই “ছোট এবং পূর্বানুমেয়” আপডেটগুলো গুরুত্বপূর্ণ। পরবর্তী মান যদি পূর্বের উপর নির্ভর করে, তাহলে updater ফর্ম ব্যবহার করুন: setCount(c => c + 1)। এটা React-এর কাজের সাথে মেলে: একাধিক আপডেট কিউ করা যেতে পারে, তারপর সেগুলো ক্রমানুসারে প্রয়োগ করা হয়।
ইমিউটেবিলিটি (অপরিবর্ত্যতা) চিত্রের অন্য অর্ধেক। অবজেক্ট বা অ্যারে inplace বদলাবেন না। পরিবর্তনের সাথে একটি নতুন অবজেক্ট তৈরি করুন। তারপর React দেখতে পাবে “এই মানটা নতুন” এবং আপনার মন ট্রেস করতে পারবে কী বদলেছে।
উদাহরণ: একটি todo আইটেম টগল করা। নিরাপদ উপায় হলো একটি নতুন অ্যারে ও যে আইটেমটি চেঞ্জ হয়েছে তার জন্য একটি নতুন todo অবজেক্ট তৈরি করা। ঝুঁকিপূর্ণ উপায় হলো বিদ্যমান অ্যারেতে todo.done = !todo.done করা।
স্টেটও সম্ভবত মিনিমাল রাখুন। একটি সাধারণ ফাঁদ হলো এমন মান রাখা যা আপনি ক্যালকুলেট করতে পারেন। যদি আপনার কাছে items এবং filter থাকে, filteredItems স্টেটে রাখবেন না। render-এ সেটা ক্যালকুলেট করুন। কম স্টেট ভ্যারিয়েবল মানে কম সম্ভাবনা মানগুলো আলাদা হয়ে ফেলার।
কী স্টেটে রাখা উচিত তার সহজ পরীক্ষা:
আপনি যদি চ্যাটের মাধ্যমে UI বানান (অন্তর্ভুক্ত Koder.ai), পরিবর্তনগুলোকে ছোট প্যাচ হিসেবে চাও: “একটা boolean ফ্ল্যাগ যোগ করুন” বা “এই লিস্টটি ইমিউটেবলি আপডেট করুন।” ছোট, স্পষ্ট পরিবর্তন জেনারেটর ও আপনার React কোডকে সঙ্গত রাখে।
Rendering UI-কে বর্ণনা করে। Effects বাইরের জগতের সাথে সিঙ্ক করে। “বাইরে” বলতে বোঝায় সেই সব জিনিস যা React নিয়ন্ত্রণ করে না: নেটওয়ার্ক কল, টাইমার, ব্রাউজার API, এবং কখনো কখনো ইম্পেরেটিভ DOM কাজ।
যদি কোনো কিছু props ও state থেকে ক্যালকুলেট করা যায়, তা সাধারণত ইফেক্টে থাকা উচিত নয়। ইফেক্টে রাখলে একটি অতিরিক্ত ধাপ যোগ হয় (render, effect চালানো, state সেট করা, আবার render)। এই অতিরিক্ত ধাপেই ফ্লিকার, লুপ, এবং “কেন এটা স্টেল?” ধরনের বাগ দেখা দেয়।
একটি সাধারণ বিভ্রান্তি: আপনার কাছে firstName এবং lastName আছে, এবং আপনি ইফেক্ট দিয়ে fullName স্টেটে রাখছেন। কিন্তু fullName আসলে side effect নয়। এটা একটি derived data। এটিকে render-এ ক্যালকুলেট করুন এবং এটা সবসময় ম্যাচ করবে।
অভ্যাস হিসেবে: UI মানগুলো render-এ নিরূপণ করুন (অথবা কিছু সস্তে না হলে useMemo-তে), এবং ইফেক্ট ব্যবহার করুন “কিছু করা” কাজগুলোর জন্য, না “কিছু খুঁজে বের করার” জন্য।
ডিপেন্ডেন্সি অ্যারেকে ভাবুন: "এই মানগুলো বদলালে বাইরের জগতের সাথে আবার সিঙ্ক করবে।" এটা পারফরম্যান্স ট্রিক নয় এবং ওয়ার্নিং চুপ করার জায়গাও নয়।
উদাহরণ: যদি আপনি যখন userId বদলে ইউজার ডিটেইল ফেচ করেন, userId ডিপেন্ডেন্সিতে থাকা উচিত। যদি ইফেক্টে token ব্যবহার করা হয়, সেটাও যোগ করুন, না হলে আপনি পুরানো টোকেন দিয়ে ফetch করতে পারেন।
ভাল গাট চেক: যদি ইফেক্ট সরালে UI বরং খারাপ হবে, সম্ভবত এটা ইফেক্ট হওয়া উচিত নয়। যদি সরালে এটা কোনো টাইমার বন্ধ করে, সাবস্ক্রিপশন বাতিল করে বা ফেচ বন্ধ করে, তখন সেটা সম্ভবত ইফেক্ট হওয়াই উচিত ছিল।
সবচেয়ে দরকারী মানসিক মডেলগুলোর একটি সহজ: ডেটা ট্রিতে নিচে যায়, এবং ব্যবহারকারীর কাজগুলো উপরে যায়।
প্যারেন্ট ভ্যালু চাইল্ডকে দেয়। চাইল্ডরা গোপনে একই মান দুই জায়গায় “own” করা উচিত নয়। তারা পরিবর্তনের অনুরোধ করে একটি ফাংশন কল করে, এবং প্যারেন্ট সিদ্ধান্ত নেয় নতুন মান কি হবে।
যখন UI-র দুই অংশে একমত থাকা দরকার, একটি জায়গায় মান রাখুন এবং নিচে পাঠান। এটাকে "lifting state" বলে। এটা একটু প্লাম্বিং মনে হতে পারে, কিন্তু খারাপ সমস্যা প্রতিরোধ করে: দুটো state যেগুলো আলাদা হয়ে যায় এবং সিঙ্ক রাখতে হ্যাক যোগ করতে হয়।
উদাহরণ: একটি search box এবং results list। যদি ইনপুট নিজে query রাখে এবং লিস্টও নিজে query রাখে, আপনি দেখতে পাবেন “ইনপুট X দেখায় কিন্তু লিস্ট Y ব্যবহার করছে।” ঠিক করা হলো query-কে এক প্যারেন্টে রাখা, তা দুই জায়গায় পাঠানো, এবং input-কে onChangeQuery(newValue) হ্যান্ডলার দেওয়া।
Lifting state সবসময় সঠিক না। যদি একটি মান শুধুমাত্র একটি কম্পোনেন্টের ভিতরেই প্রাসঙ্গিক হয়, সেখানে রাখা ঠিক। state যেখানে বেশি কাছাকাছি থাকবে সাধারণত কোড পড়তে সহজ করে তোলে।
একটি ব্যবহারিক সীমা:
আপনি অনিশ্চিত হলে, নিচের সিগন্যালগুলো খুঁজুন: দুই কম্পোনেন্ট একই মান আলাদা ভাবে দেখায়; এক জায়গার অ্যাকশন অন্য জায়গায় কিছু আপডেট করতে হয়; আপনি বারবার props কে state-এ কপি করছেন “জাস্ট ইন কেস”; বা আপনি দুই মান মিল রাখার জন্য ইফেক্ট যোগ করছেন।
এই মডেল চ্যাট-ভিত্তিক টুলে কাজ করার সময়ও সাহায্য করে: প্রতিটি শেয়ার্ড স্টেটের জন্য এক মালিক চাও, তারপর হ্যান্ডলার জেনারেট কর যা উপরে প্রবাহিত হয়।
একটা ছোট ফিচার বেছে নিন যা আপনার মাথায় ধারণা ধরে রাখতে সক্ষম। একটি ভালো উদাহরণ হলো একটি সার্চযোগ্য তালিকা যেখানে আইটেম ক্লিক করলে বিস্তারিত মডালে দেখা যায়।
প্রথমে UI অংশগুলো ও সম্ভাব্য ইভেন্টগুলো স্কেচ করুন। কোড চিন্তা করবেন না। ব্যবহারকারী কি করতে পারে এবং কি দেখতে পারে সেটা ভাবুন: এখানে একটি search input, একটি লিস্ট, একটি selected row হাইলাইট এবং একটি modal আছে। ইভেন্টগুলো হলো সার্চ টাইপ করা, আইটেম ক্লিক করা, মডাল খোলা এবং মডাল বন্ধ করা।
এখন “স্টেট আঁকুন।” কয়েকটি মান লিখে ফেলুন যেগুলো স্টোর করতে হবে এবং ঠিক করুন কে মালিক। একটি সহজ নিয়ম কাজ করে: যেগুলো ব্যবহার করবে তাদের সবচেয়ে নিকটতম কমন প্যারেন্ট মালিক হবে।
এই ফিচারের জন্য সংরক্ষিত state খুবই ছোট হতে পারে: query (string), selectedId (id বা null), এবং isModalOpen (boolean)। লিস্ট query পড়ে এবং আইটেম রেন্ডার করে। মডাল selectedId পড়ে বিস্তারিত দেখায়। যদি লিস্ট ও মডাল দুইটেই selectedId লাগে, টা প্যারেন্টে রাখুন, উভয় জায়গায় না।
এরপর derived data আলাদা করুন। filtered list হল derived: filteredItems = items.filter(...)। এটাকে state-এ রাখবেন না কারণ এটা সবসময় items এবং query থেকে পুনর্গণনা করা যায়। Derived data স্টেট করলে মানগুলো আলাদা হয়ে যেতে পারে।
এরপরই জিজ্ঞেস: কি ইফেক্ট দরকার? যদি items মনে রাখতে আছে, দরকার নেই। যদি টাইপ করার পর সার্ভার থেকে ফলাফল আনা উচিত, তখন দরকার। মডাল বন্ধ করলে যদি কোন কিছু সেভ করা লাগে, তখন দরকার। ইফেক্ট সিঙ্কের জন্য, না UI ওয়্যারিংয়ের জন্য।
শেষে কয়েকটা এজ কেস টেস্ট করুন:
selectedId এখনও বৈধ কি?যদি আপনি কাগজে এসব উত্তর দিতে পারেন, React কোড সাধারণত সোজা হয়ে যায়।
অধিকাংশ React বিভ্রান্তি সিনট্যাক্স নিয়ে নয়। এটা ঘটে যখন আপনার কোড আপনার মাথায় থাকা সরল গল্পের সাথে মেলে না।
Derived state রাখা। আপনি fullName স্টেটে রাখেন যদিও এটা কেবল firstName + lastName। এটা কাজ করে যতক্ষণ না egyik ফিল্ড বদলে যায় আর অন্যটি না হয়, তখন UI stale দেখায়।
Effect লুপ। একটি ইফেক্ট ডেটা ফেচ করে, state সেট করে, এবং ডিপেন্ডেন্সি তালিকা এটাকে আবার চালায়। লক্ষণ হচ্ছে পুনরাবৃত্ত অনুরোধ, ঝাঁকুনি UI, বা এমন state যা কখনোই স্থির হয় না।
Stale closures. একটি ক্লিক হ্যান্ডলার পুরানো মান পড়ে (যেমন পুরানো কাউন্টার বা ফিল্টার)। লক্ষণ: “আমি ক্লিক করলাম, কিন্তু এটা গতকের মান ব্যবহার করলো।”
গ্লোবাল state সবখানে। সব UI ডিটেইল গ্লোবাল স্টোরে রাখা হলে কি মালিক তা বোঝা কঠিন হয়ে যায়। লক্ষণ: আপনি একটি জিনিস বদলালে তিনটি স্ক্রিন হঠাৎ জবাব দেয় অপ্রত্যাশিতভাবে।
নেস্টেড অবজেক্ট মিউটেশন। আপনি অবজেক্ট বা অ্যারে ইনপ্লেস আপডেট করেন এবং ভাবেন কেন UI আপডেট হল না। লক্ষণ: “ডেটা বদলে গেছে, কিন্তু কিছু re-render হয়নি।”
কনক্রিট উদাহরণ: একটি “search and sort” প্যানেল। যদি আপনি filteredItems state-এ রাখেন, নতুন ডাটা এলে এটা items থেকে ভিন্ন হয়ে যেতে পারে। বদলে ইনপুটগুলো (search text, sort choice) স্টোর করুন এবং রেন্ডার মধ্যে filtered list গণনা করুন।
ইফেক্টের ক্ষেত্রে, সেগুলো বাইরের জগতের সাথে সিঙ্ক করার জন্য রাখুন (fetching, subscriptions, timers)। যদি কোনো ইফেক্ট বেসিক UI কাজ করছে, সাধারণত সেটা render বা একটি ইভেন্ট হ্যান্ডলারেই থাকা উচিত।
চ্যাট দিয়ে কোড জেনারেট বা এডিট করার সময় এই ভুলগুলো দ্রুত দেখা যায় কারণ পরিবর্তনগুলো বড় টুকরোতেই আসতে পারে। একটি ভাল অভ্যাস হলো অনুরোধগুলো ownership-ভিত্তিক করা: “এই মানটির truth কোথায়?” এবং “এটা কি গণনা করা যায় স্টেটে রাখা ছাড়াই?”
যখন আপনার UI অনিয়মিত মনে হয়, সাধারণত এটা “অধিক React” নয়; এটা সাধারণত খুব বেশি স্টেট, ভুল জায়গায়, এমন কাজে লাগানো যা করা উচিত নয়।
আরও useState যোগ করার আগে থামুন এবং জিজ্ঞেস করুন:
ছোট উদাহরণ: search box, filter dropdown, list। যদি আপনি query এবং filteredItems দুটোই state-এ রাখেন, এখন আপনার কাছে দুইটি truth আছে। বদলে query ও filter state-এ রাখুন, তারপর filteredItems পুরো লিস্ট থেকে render-এ derive করুন।
এটি চ্যাট টুল দিয়ে দ্রুত তৈরি করার সময়ও গুরুত্বপূর্ণ। গতি ভালো, কিন্তু বারবার জিজ্ঞেস করুন: “আমরা স্টেট যোগ করেছি, নাকি দুর্ঘটনাক্রমে একটি derived value যোগ করেছি?” যদি এটা derived হয়, সেই state মুছুন এবং render-এ ক্যালকুলেট করুন।
একটি ছোট টিম একটি অ্যাডমিন UI বানাচ্ছে: অর্ডারের টেবিল, কয়েকটি ফিল্টার, এবং একটি ডায়ালগ অর্ডার এডিট করার জন্য। প্রথম অনুরোধটা অস্পষ্ট: “ফিল্টার যোগ করো এবং একটি edit popup.” এটা সরল শোনালেও প্রায়ই র্যান্ডম স্টেট ছড়িয়ে পড়ে।
এটাকে কনক্রিট করে তুলুন স্টেট ও ইভেন্টগুলোর মাধ্যমে। “ফিল্টার” বলার বদলে স্টেটে নাম দিন: query, status, dateRange। “edit popup” বলার বদলে ইভেন্টের নাম দিন: “user clicks Edit on a row.” তারপর সিদ্ধান্ত নিন প্রতিটি স্টেট কে কোন মালিক (page, table, বা dialog) এবং কি derive করা যায় (যেমন filtered list)।
কিছু উদাহরণ প্রম্পট যা মডেলটিকে অক্ষুণ্ণ রাখে (এগুলো চ্যাট-বিল্ডারেও কাজ করে, যেমন Koder.ai):
OrdersPage that owns filters and selectedOrderId. OrdersTable is controlled by filters and calls onEdit(orderId).”visibleOrders from orders and filters. Do not store visibleOrders in state.”EditOrderDialog that receives order and open. When saved, call onSave(updatedOrder) and close.”filters to the URL, not to compute filtered rows.”UI জেনারেট বা আপডেট করার পর দ্রুত একটি চেক করুন: প্রতিটি state মানের এক মালিক আছে, derived মানগুলো স্টোর করা নেই, effects কেবল বাইরের জগতের সাথে সিঙ্কিং করছে (URL, নেটওয়ার্ক, স্টোরেজ), এবং ইভেন্টগুলো প্রপস হিসেবে নেমে এবং কলব্যাক হিসেবে উপরে উঠছে।
স্টেট পূর্বানুমেয় হলে ইটারেশন নিরাপদ লাগে। আপনি টেবিল লেআউট বদলাতে, নতুন ফিল্টার যোগ করতে, বা ডায়ালগ ফিল্ড টুইক করতে পারেন এটা ভাবার ছাড়া যে কোন লুকানো স্টেট বাদে কি ভেঙে যাবে।
গতি তখনই কাজে লাগে যখন অ্যাপটি বোঝা সহজ থাকে। সবচেয়ে সহজ প্রতিরক্ষা হলো এই মানসিক মডেলগুলোকে একটি চেকলিস্ট হিসেবে ব্যবহার করা কোড লিখার (বা জেনারেট করার) আগে।
প্রতিটি ফিচার শুরু করুন একইভাবে: আপনি কোন state দরকার, কোন ইভেন্টগুলো তা বদলায়, এবং কে মালিক তা লিখে নিন। যদি আপনি বলতে না পারেন, “এই কম্পোনেন্ট এই state own করে, এবং এই ইভেন্টগুলো সেটা আপডেট করে,” তাহলে সম্ভবত আপনি scattered state এবং অপ্রত্যাশিত re-render পেয়ে যাবেন।
যদি আপনি চ্যাটের মাধ্যমে বানান, planning mode-এ শুরু করুন। কম্পোনেন্ট, state shape, এবং transition গুলো সরল ভাষায় বর্ণনা করে কোড জেনারেটের আগে। উদাহরণ: “একটি filter panel query state আপডেট করে; results list query থেকে derive করে; একটি আইটেম সিলেক্ট করলে selectedId সেট হবে; বন্ধ করলে এটি ক্লিয়ার করে।” যখন এটা পরিষ্কার পড়ায়, UI জেনারেট করা যন্ত্রগত ধাপ হয়ে যায়।
আপনি যদি Koder.ai (koder.ai) ব্যবহার করছেন React কোড জেনারেট করতে, দ্রুত একটি স্যানিটি পাস করা মূল্যবান: প্রতিটি state মানের জন্য এক স্পষ্ট মালিক, UI state থেকে derive, effects কেবল সিঙ্কিংয়ের জন্য, এবং ডুপ্লিকেট truth নেই।
তারপর ছোট ধাপে ইটারেট করুন। আপনি যদি স্টেট স্ট্রাকচার পরিবর্তন করতে চান (উদাহরণ: কয়েকটি boolean থেকে একটি single status field), আগে একটি স্ন্যাপশট নিন, পরীক্ষা করুন, এবং যদি মানসিক মডেল খারাপ হয় তাহলে রোলব্যাক করুন। যখন গভীর পর্যালোচনা বা হ্যান্ডঅফ লাগবে, সোর্স কোড এক্সপোর্ট করলে সহজে উত্তর দেওয়া যায়: স্টেট শেপ কি এখনো UI-র গল্প বলে?
শুরু করার জন্য একটি ভাল মডেল হল: UI = f(state, props)। আপনার কম্পোনেন্টগুলো DOM "এডিট" করে না; তারা বর্তমান ডেটার জন্য কি দেখা উচিত তা বর্ণনা করে। যদি স্ক্রিন ভুল দেখায়, DOM না দেখে সেই UI তৈরি করা state/props পরীক্ষা করুন।
Props হল ইনপুট প্যারেন্ট থেকে; আপনার কম্পোনেন্টগুলোকে এগুলো রিড-অনলি হিসেবে দেখা উচিত। State হল মেমোরি যা একটি কম্পোনেন্ট (অথবা আপনি যাকে মালিক বানান) own করে। যদি একটি মান শেয়ার করা লাগবে, তবে এটাকে উপরে উঠান এবং প্রপস হিসেবে নীচে পাঠান।
একটি re-render মানে React আপনার কম্পোনেন্ট ফাংশন পুনরায় চালায় এবং পরের UI বর্ণনা গণনা করে। এটা স্বয়ংক্রিয়ভাবে পুরো পেজ রি-পেইন্ট করে এমনটা নয়। React তারপর আসল DOM-এ যতটুকু পরিবর্তন প্রয়োজন সেটাই করে।
কারণ state আপডেটগুলি নির্ধারিত (scheduled); তাৎক্ষণিক অ্যাসাইনমেন্ট নয়। যদি পরবর্তী মান পূর্বের উপর নির্ভর করে, তাহলে আপডেটার ফর্ম ব্যবহার করুন যাতে স্টেল মানে নির্ভর না করতে হয়:
setCount(c => c + 1)এটি একাধিক queued আপডেট থাকলেও সঠিক থাকবে।
যেকোনো কিছু যা আপনি বিদ্যমান ইনপুট থেকে গণনা করতে পারেন সেটা স্টেটে রাখবেন না। ইনপুটগুলো স্টোর করুন, বাকি সব render এর সময় গণনা করুন।
উদাহরণ:
items, filtervisibleItems = items.filter(...)এভাবে মানগুলি sync থেকে বিচ্ছিন্ন হবে না।
ইফেক্টগুলো ব্যবহার করুন যখন আপনি React যে জিনিসগুলো নিয়ন্ত্রণ করে না সেগুলোকে সিঙ্ক করতে চান: ফেচ, সাবস্ক্রিপশন, টাইমার, ব্রাউজার API, বা ইম্পেরেটিভ DOM কাজ।
UI মানগুলো ক্যালকুলেট করার জন্য ইফেক্ট ব্যবহার করবেন না—সেগুলো render এ (অথবা খুব খরচি হলে useMemo-তে) ক্যালকুলেট করুন।
ডিপেন্ডেন্সি অ্যারে ভাবুন: “এই মানগুলো বদলে গেলে বাইরে সিঙ্ক আবার চালাতে হবে।” এটি পারফরম্যান্স ট্রিক নয় বা ওয়ার্নিং চেপে ধরবার জায়গা নয়।
উদাহরণ: যদি আপনি userId বদলালে ইউজার ডিটেইল ফেচ করেন, তবে userId ডিপেন্ডেন্সিতে থাকা উচিত। ইফেক্টে পড়া প্রতিটি রিএক্টিভ মান অন্তর্ভুক্ত করুন, অন্যথায় আপনি পুরানো টোকেন দিয়ে ফেচ করতে পারেন।
সাধারণ পরীক্ষা: যদি ইফেক্টটি সরালে UI ভুল হবে, সম্ভবত সেটা আসল ইফেক্ট ছিল না। যদি সরালে টাইমার বন্ধ হবে, সাবস্ক্রিপশন বাতিল হবে বা ফেচ বন্ধ হবে—তবে সেটা সম্ভবত ইফেক্ট হওয়াই উচিত ছিল।
যদি UI-র দু’টি অংশকে একইভাবে মান দেখাতে হয়, তাহলে তাদের closest common parent-এ state রাখুন, মান নীচে পাঠান এবং পরিবর্তনের জন্য callback উপরে পাঠান।
দ্রুত পরীক্ষা: যদি আপনি একই মান দুই জায়গায় ডুপ্লিকেট করে রেখে সিঙ্ক রাখার জন্য ইফেক্ট লিখছেন, তাহলে সম্ভবত সেই state একটাই মালিক থাকা উচিত।
সাধারণত হ্যান্ডলারগুলো পুরানো মান “ক্যাপচার” করলে এটি হয়। সাধারণ সমাধানগুলো:
setX(prev => ...)যদি ক্লিকে "গতকালের মান" ব্যবহার হচ্ছে, তাহলে suspect করুন যে এটা stale closure।
একটি ছোট পরিকল্পনা দিয়ে শুরু করুন: কম্পোনেন্টগুলো, কোনটা state মালিক, এবং ইভেন্টগুলো কী। তারপর কোড জেনারেট করুন ছোট প্যাচ হিসেবে (একটা state field যোগ করা, একটা হ্যান্ডলার যোগ করা, একটা derived value)।
চ্যাট বিল্ডার ব্যবহার করলে (উদাহরণ: Koder.ai), অনুরোধগুলো এইভাবে করুন:
এভাবে জেনারেট করা কোড React-র মানসিক মডেলের সাথে সংগত থাকে।