স্টেট ভেরিয়েবল নরমাল জাবাস্ক্রিপ্ট ভেরিয়েবলের মতো মনে হলেও এটা মোটেও জাবাস্ক্রিপটের নরমাল ভেরিয়েবল এর মতো কাজ করেনা। চলুন বিস্তারিত জেনে নেয়া যাক।
Rendering takes a snapshot in time:
এর মানে হলো রিয়াক্ট তার প্রতিটা রেন্ডারে একটা করে snapshot
নেয়। এবং তা মনে রাখে। যখনি কোন স্টেট এর ভ্যালু চেঞ্জ হয় তখন রিয়াক্ট কম্পোনেন্টকে রি-রেন্ডার করে এবং পরের রেন্ডারে গিয়ে তার ভ্যালু আপডেট হয়। তার মানে হলো আমরা নরমাল ভেরিয়েবল এ যেমন কোন ভ্যালু চেঞ্জ করলে পরের লাইনেই তা এক্সেস করতে পারি কিন্তু রিয়াক্টে তা পারিনা,কেননা রিয়াক্ট ইনপ্লেস ভ্যালু চেঞ্জ করেনা। ভ্যালুটা চেঞ্জ হয় তার পরের রেন্ডারে।
একটা উদাহরণের মাধ্যমে বুঝা যাকঃ
import { useState } from "react";
export default function App() {
const [number, setNumber] = useState(1);
function handleClick() {
setNumbers(number + 5);
console.log(number);
}
return <button onClick={handleClick}>Incriment the number</button>;
}
উপরের কোডটার কনসলে আউটপুট কত আশার কথা? স্বাভাবিক ভাবে দেখলে মনে হয় যে আউটপুত 6
আসার কথা। কিন্তু না , এখানে আউটপুট আসবে 1
। কারণ রিয়াক্ট তার স্টেট চেঞ্জ হলেই ডিরেক্ট ভ্যালু চেঞ্জ করে দেয়না, তাই সেই ভ্যালুটা পরের লাইনগুলোতে এক্সেস করা যায়না।
যেই হেন্ডেলার ফাংশনে setter function
কল করা হয়েছে সেই হেন্ডেলার এর পুরো কোডটা এক্সিকিউট হয়ে যাওয়ার পর রি-রেন্ডার ট্রিগার হয় এবং পরের রেন্ডারে আপডেটেড ভ্যালু পাওয়া যায়।
আরেকটা উদাহরণ যদি আমারা দেখিঃ
import { useState } from "react";
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button
onClick={() => {
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);
}}>
+3
</button>
</>
);
}
এখানে একটা বাটনে তিনবার setter function
কল করা হয়েছে এবং তিনবার স্টেট এর ভ্যালু আপডেট করা হয়েছে। এই কোডটা রান করে আমরা যদি বাটনে ক্লিক করি তাহলে আউটপুট কত আসার কথা- 3
?
কিন্তু না আউটপুট আসবে 1
।
যেহেতু স্টেট শুধুমাত্র পরের রেন্ডারে চেঞ্জ হয় তাই প্রথম রেন্ডারে স্টেট এর ভ্যালু ছিল 0
। তাই প্রথম রেন্ডারে তিনবার setter function
কল হলেও তিনবার এ সে স্টেটের ইনিশিয়াল ভ্যালু পাবে 0
। আর তাই নাম্বার
এর আউটপুট আসবে 1
<button
onClick={() => {
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);
}}>
+3
</button>
এখানে যেটা হচ্ছে প্রথম রেন্ডারে প্রথমবার যখন setNumber(number + 1)
করা হচ্ছে তখন আসলে 0 + 1 = 1
করা হচ্ছে যা পরের রেন্ডারে আউটপুটে আসবে,
কিন্তু পরের রেন্ডারে যাওয়ার আগে আরও দুইবার setNumber(number + 1)
করা হয়েছে,
তার মানে তখনও কিন্তু 0 + 1 = 1
ই করা হচ্ছে ।
তারমানে শেষবার যখন setNumber(number + 1)
করা হয়েছে, তখন কিন্তু 0 + 1 = 1
ই করা হয়েছে এবং স্টেট তার মেমরিতে 1
নিয়েই পরের রেন্ডার ট্রিগার করেছে এবং আউটপুটে 1
প্রিন্ট হয়েছে ।
<button
onClick={() => {
setNumber(0 + 1);
setNumber(0 + 1);
setNumber(0 + 1);
}}>
+3
</button>
আবার যদি কোডটা এমন হয়ঃ
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button
onClick={() => {
setNumber(number + 5);
setTimeout(() => {
alert(number);
}, 3000);
}}>
+5
</button>
</>
);
}
এখানে বাটনে নাম্বারের স্টেট চেঞ্জ করা হয়েছে এবং একটা setTimeout()
কল করা হয়েছে ৩ সেকেন্ডের জন্য। এবং তাতে নাম্বার এর ভ্যালুটা এলার্টে নেয়া হয়েছে।
এখানেও হয়তো মনে হতে পারে যে নাম্বার এর ভ্যালু এলার্টে 5
আসবে,কেননা যতক্ষণে ৩ সেকেন্ড টাইমার শেষ হবে ততক্ষণে স্টেট রি-রেন্ডার হয়ে যাবে এবং আমরা এলার্টে আপডেটেড ভ্যালু পাবো ।
কিন্তু না এখানেও ব্যাপারটাকে snapshot
হিসেবে চিন্তা করতে হবে, এখানে timeOut
টা তিন সেকেন্ড পরে হলেও যখন টাইমআউট শুরু হয়েছে তখন কিন্তু সে number
এর ভ্যালু 0
নিয়েই গিয়েছে, তাই টাইমার যতই নিয়ে যাক প্রথম রেন্ডারে সে তাই পাবে যেটা তার ইনিশিয়াল ভ্যালু।
অর্থাৎ রিয়াক্টের একটা রেন্ডারে কখনই সরাসরি ভ্যালু চেঞ্জ হয়না, বরং স্টেট চেঞ্জ হলে একটা রি-রেন্ডার ট্রিগার হয় এবং পরের রেন্ডারে গিয়ে তার আপডেটেড ভ্যালু পাওয়া যায়।