স্টেট হিসেবে একটি স্ন্যাপশট
স্টেট ভেরিয়েবলগুলি দেখতে নিয়মিত জাভাস্ক্রিপ্ট ভেরিয়েবলের মতো লাগতে পারে যা আপনি রিড করতে পারেন, আপডেট করতে পারেন। তবে, স্টেট একটি স্ন্যাপশটের মতো আচরণ করে। স্টেট সেট করা হলে আপনার ইতিমধ্যেই থাকা স্টেট ভেরিয়েবলটি পরিবর্তন করে না, বরং একটি পুনরায় রেন্ডার হয়ে ট্রিগার করে।
রিএক্ট এর স্টেট নিয়মিত জাভাস্ক্রিপ্টের ভেরিয়েবলের মতো না
অবস্থা ভেরিয়েবলগুলো হয়তো নিয়মিত জাভাস্ক্রিপ্টের ভেরিয়েবলের মতোই দেখাবে যেগুলো আপনি রিড করতে পারেন, আপডেট করতে পারবেন। তবে, তবে রিক্টের স্টেট ভেরিয়েবল গুলো আরও বেশি করে একটি স্ন্যাপশটের মতো আচরণ করে। এটি সেট করলে আপনার ইতিমধ্যে থাকা অবস্থা ভেরিয়েবল পরিবর্তিত হয় না, বরং একটি পুনঃনির্মাণ হয়ে ট্রিগার করে।
আপনি কী শিখবেন
- অবস্থা সেট করা কীভাবে পুনঃনির্মাণ ট্রিগার করে
- কখন এবং কীভাবে অবস্থা আপডেট হয়
- আপনি এটি সেট করার পরে কেন অবস্থা অবিলম্বে আপডেট হয় না
- ইভেন্ট হ্যান্ডলার কীভাবে অবস্থার একটি "স্নাপশট" অ্যাক্সেস করে
স্টেট সেট করা হলে কম্পোনেন্ট রেন্ডার হয়ে ট্রিগার করে
আপনি হয়তো ভাবতে পারেন যে আপনার ইউজার ইন্টারফেস সরাসরি ব্যবহারকারীর ইভেন্টের প্রতিক্রিয়া হিসেবে পরিবর্তিত হয়, যেমন একটি ক্লিক। React-এ এটি একটু ভিন্নভাবে কাজ করে। আগের পৃষ্ঠায়, আপনি দেখেছেন যে স্টেট সেট করা React-কে একটি রেন্ডার অনুরোধ করে। এর মানে হল যে একটি ইন্টারফেসকে ইভেন্টের প্রতি প্রতিক্রিয়া জানাতে, আপনাকে স্টেট আপডেট করতে হবে।
এই উদাহরণে, যখন আপনি “send” চাপেন, setIsSent(true)
React-কে UI পুনরায় রেন্ডার করতে বলে:
import { useState } from "react";
export default function Form() {
const [isSent, setIsSent] = useState(false);
const [message, setMessage] = useState("Hi!");
if (isSent) {
return <h1>Your message is on its way!</h1>;
}
return (
<form
onSubmit={(e) => {
e.preventDefault();
setIsSent(true);
sendMessage(message);
}}
>
<textarea
placeholder="Message"
value={message}
onChange={(e) => setMessage(e.target.value)}
/>
<button type="submit">Send</button>
</form>
);
}
function sendMessage(message) {
// ...
}
এখানে কী ঘটে যখন আপনি বোতামটি চাপেন:
onSubmit
ইভেন্ট হ্যান্ডলারটি কার্যকর হয়।setIsSent(true)
isSent
-কেtrue
সেট করে এবং একটি নতুন রেন্ডারকে কিউ করে।- React নতুন
isSent
মান অনুযায়ী কম্পোনেন্টটি পুনরায় রেন্ডার করে।
এই প্রক্রিয়াটি দেখায় কিভাবে স্টেট আপডেট করা রেন্ডারকে ট্রিগার করে এবং আপনার ইউজার ইন্টারফেসকে ইভেন্টের প্রতি প্রতিক্রিয়া জানাতে সক্ষম করে।
স্টেট এবং রেন্ডারিং এর মধ্যে সম্পর্কের আরও গভীরভাবে দেখা যাক
রেন্ডারিং একটি নির্দিষ্ট সময়ের একটি স্ন্যাপশট গ্রহণ করে
"রেন্ডারিং" মানে হল React আপনার কম্পোনেন্টকে কল করছে, যা একটি ফাংশন। আপনি সেই ফাংশন থেকে যে JSX ফিরিয়ে দেন তা নির্দিষ্ট সময়ে UI এর একটি স্ন্যাপশটের মতো। এর props, ইভেন্ট হ্যান্ডলার এবং লোকাল ভেরিয়েবল সবই সেই সময়ের স্টেট ব্যবহার করে গণনা করা হয়।
একটি ফটোগ্রাফ বা একটি সিনেমার ফ্রেমের বিপরীতে, আপনি যে UI "স্ন্যাপশট" ফিরিয়ে দেন তা ইন্টারেক্টিভ। এটি ইভেন্ট হ্যান্ডলারগুলির মতো যুক্তি অন্তর্ভুক্ত করে যা ইনপুটগুলির প্রতিক্রিয়া হিসাবে কী ঘটে তা নির্দিষ্ট করে। React স্ক্রীনকে এই স্ন্যাপশটের সাথে তুলনা করে আপডেট করে এবং ইভেন্ট হ্যান্ডলারগুলিকে সংযুক্ত করে। ফলস্বরূপ, একটি বাটনে চাপলে আপনার JSX থেকে ক্লিক হ্যান্ডলার ট্রিগার হবে।
যখন React একটি কম্পোনেন্ট পুনরায় রেন্ডার করে:
- React আপনার ফাংশনটিকে আবার কল করে।
- আপনার ফাংশনটি একটি নতুন JSX স্ন্যাপশট ফিরিয়ে দেয়।
- React তারপর আপনার ফাংশন যে স্ন্যাপশটটি ফিরিয়েছে তার সাথে তুলনা করে স্ক্রীন আপডেট করে।
একটি কম্পোনেন্টের মেমরি হিসেবে, স্টেট একটি সাধারণ ভেরিয়েবলের মতো নয় যা আপনার ফাংশন ফেরত দেওয়ার পরে অদৃশ্য হয়ে যায়। স্টেট আসলে React এর মধ্যে "বেঁচে থাকে"— যেন একটি শেলফে! আপনার ফাংশনের বাইরে। যখন React আপনার কম্পোনেন্টকে কল করে, এটি আপনাকে সেই নির্দিষ্ট রেন্ডারের জন্য স্টেটের একটি স্ন্যাপশট দেয়। আপনার কম্পোনেন্ট তার JSX-এ স্টেট মানগুলি ব্যবহার করে একটি নতুন সেট props এবং ইভেন্ট হ্যান্ডলারগুলির সাথে UI এর একটি স্ন্যাপশট ফিরিয়ে দেয়!
এই কাজটি কীভাবে কাজ করে তা দেখানোর জন্য এখানে একটি ছোট পরীক্ষা রয়েছে। এই উদাহরণে, আপনি আশা করতে পারেন যে “+3” বোতামটি ক্লিক করলে কাউন্টারটি তিনবার ইনক্রিমেন্ট হবে কারণ এটি setNumber(number + 1)
তিনবার কল করে।
দেখুন যখন আপনি “+3” বোতামটি ক্লিক করেন তখন কী ঘটে:
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>
</>
);
}
দেখুন যে number প্রতি ক্লিকের জন্য শুধুমাত্র একবার ইনক্রিমেন্ট হয়!
স্টেট সেট করা হলে শুধুমাত্র পরবর্তী রেন্ডারের জন্য এটিকে পরিবর্তন করে। প্রথম রেন্ডারের সময়, number ছিল 0। এই কারণেই, সেই রেন্ডারের onClick
হ্যান্ডলারে, setNumber(number + 1)
কল করার পরেও number এর মান 0 থাকে:
<button
onClick={() => {
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);
}}
>
+3
</button>
এই বাটনে onClick
হ্যান্ডলারটি React-কে নিম্নলিখিত কাজগুলি করতে বলে:
setNumber(number + 1)
: number হল 0 তাইsetNumber(0 + 1)
। React পরবর্তী রেন্ডারে number-কে 1-এ পরিবর্তন করার প্রস্তুতি নিচ্ছে।setNumber(number + 1)
: number হল 0 তাইsetNumber(0 + 1)
। React পরবর্তী রেন্ডারে number-কে 1-এ পরিবর্তন করার প্রস্তুতি নিচ্ছে।setNumber(number + 1)
: number হল 0 তাইsetNumber(0 + 1)
। React পরবর্তী রেন্ডারে number-কে 1-এ পরিবর্তন করার প্রস্তুতি নিচ্ছে।
যদিও আপনি setNumber(number + 1)
তিনবার কল করেছেন, এই রেন্ডারের ইভেন্ট হ্যান্ডলারে number সর্বদা 0, তাই আপনি স্টেটটি তিনবার 1-এ সেট করেছেন। এই কারণেই, আপনার ইভেন্ট হ্যান্ডলার শেষ হওয়ার পরে, React number সমান 1 নিয়ে কম্পোনেন্টটি পুনরায় রেন্ডার করে, 3 নয়।
আপনি আপনার কোডে স্টেট ভেরিয়েবলগুলিকে তাদের মান দিয়ে মানসিকভাবে প্রতিস্থাপন করে এটিও চিত্রিত করতে পারেন। যেহেতু এই রেন্ডারের জন্য number স্টেট ভেরিয়েবলটি 0, এর ইভেন্ট হ্যান্ডলারটি এভাবে দেখায়:
<button
onClick={() => {
setNumber(0 + 1);
setNumber(0 + 1);
setNumber(0 + 1);
}}
>
+3
</button>
পরবর্তী রেন্ডারের জন্য, number 1, তাই সেই রেন্ডারের ক্লিক হ্যান্ডলারটি এভাবে দেখায়:
<button
onClick={() => {
setNumber(1 + 1);
setNumber(1 + 1);
setNumber(1 + 1);
}}
>
+3
</button>
এই কারণেই বোতামটি আবার ক্লিক করলে কাউন্টারটি 2 এ সেট হবে, তারপরে পরবর্তী ক্লিকে 3 এ সেট হবে, এবং এভাবে চলতে থাকবে।
সময়ের সাথে সাথে স্টেট
আচ্ছা, এটা মজার ছিল। অনুমান করার চেষ্টা করুন যে এই বোতামটি ক্লিক করলে কী এলার্ট দেখাবে:
import { useState } from "react";
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button
onClick={() => {
setNumber(number + 5);
alert(number);
}}
>
+5
</button>
</>
);
}
যদি আপনি পূর্বের প্রতিস্থাপন পদ্ধতি ব্যবহার করেন, আপনি অনুমান করতে পারেন যে এলার্টটি "0" দেখাবে:
setNumber(0 + 5);
alert(0);
কিন্তু যদি আপনি এলার্টে একটি টাইমার যোগ করেন, তাহলে এটি শুধুমাত্র কম্পোনেন্টটি পুনরায় রেন্ডার হওয়ার পরে ফায়ার করবে? এটি "0" বা "5" বলবে? অনুমান করুন!
import { useState } from "react";
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button
onClick={() => {
setNumber(number + 5);
setTimeout(() => {
alert(number);
}, 3000);
}}
>
+5
</button>
</>
);
}
আশ্চর্য? যদি আপনি প্রতিস্থাপন পদ্ধতি ব্যবহার করেন, আপনি স্টেটের "স্ন্যাপশট" এলার্টে পাঠানোর বিষয়টি দেখতে পারেন।
setNumber(0 + 5);
setTimeout(() => {
alert(0);
}, 3000);
স্টেট React-এ সংরক্ষিত হতে পারে এলার্ট চালানোর সময় পরিবর্তিত হয়েছে, কিন্তু এটি ব্যবহারকারী এর সাথে ইন্টারেক্ট করার সময় স্টেটের একটি স্ন্যাপশট ব্যবহার করে নির্ধারিত হয়েছিল!
একটি স্টেট ভেরিয়েবলের মান একটি রেন্ডারের মধ্যে কখনই পরিবর্তিত হয় না, এমনকি যদি এর ইভেন্ট হ্যান্ডলারের কোড অ্যাসিনক্রোনাস হয়। সেই রেন্ডারের onClick
এর ভিতরে, setNumber(number + 5)
কল করার পরেও number
এর মান 0 থাকে। React আপনার কম্পোনেন্ট কল করে UI এর স্ন্যাপশট নেওয়ার সময় এর মান "স্থির" হয়েছিল।
এর একটি উদাহরণ এখানে দেওয়া হয়েছে যে কীভাবে এটি আপনার ইভেন্ট হ্যান্ডলারগুলিকে টাইমিং ভুলের জন্য কম ঝুঁকিপূর্ণ করে তোলে। নীচে একটি ফর্ম রয়েছে যা পাঁচ সেকেন্ডের বিলম্ব সহ একটি বার্তা পাঠায়। এই পরিস্থিতি কল্পনা করুন:
- আপনি "Send" বোতাম টিপুন, "Hello" কে Alice এ পাঠান।
- পাঁচ সেকেন্ডের বিলম্ব শেষ হওয়ার আগে, আপনি "To" ফিল্ডের মান পরিবর্তন করে "Bob" এ করেন।
আপনি কী আশা করেন যে এলার্টটি কী প্রদর্শন করবে? এটি কি "You said Hello to Alice" প্রদর্শন করবে? নাকি এটি "You said Hello to Bob" প্রদর্শন করবে? আপনার জানা তথ্যের উপর ভিত্তি করে একটি অনুমান করুন, এবং তারপর এটি চেষ্টা করুন:
import { useState } from "react";
export default function Form() {
const [to, setTo] = useState("Alice");
const [message, setMessage] = useState("Hello");
function handleSubmit(e) {
e.preventDefault();
setTimeout(() => {
alert(`You said ${message} to ${to}`);
}, 5000);
}
return (
<form onSubmit={handleSubmit}>
<label>
To:{" "}
<select value={to} onChange={(e) => setTo(e.target.value)}>
<option value="Alice">Alice</option>
<option value="Bob">Bob</option>
</select>
</label>
<textarea
placeholder="Message"
value={message}
onChange={(e) => setMessage(e.target.value)}
/>
<button type="submit">Send</button>
</form>
);
}
React একটি রেন্ডারের ইভেন্ট হ্যান্ডলারগুলির মধ্যে স্টেট মানগুলি "স্থির" রাখে। কোড চলাকালীন স্টেট পরিবর্তিত হয়েছে কিনা তা নিয়ে আপনাকে চিন্তা করতে হবে না।
কিন্তু যদি আপনি পুনরায় রেন্ডার করার আগে সর্বশেষ স্টেট পড়তে চান? আপনি একটি স্টেট আপডেটার ফাংশন ব্যবহার করতে চাইবেন, যা পরবর্তী পৃষ্ঠায় আচ্ছাদিত!
সংক্ষিপ্তসার
- নতুন স্টেট সেট করা হলে, একটি নতুন রেন্ডারের অনুরোধ করে।
- রিঅ্যাক্ট স্টেটকে আপনার কম্পোনেন্টের বাইরে সংরক্ষণ করে, যেন একটি শেলফে।
- আপনি যখন useState কল করেন, রিঅ্যাক্ট আপনাকে সেই রেন্ডারের জন্য অবস্থার একটি স্ন্যাপশট তৈরি করে।
- ভেরিয়েবল এবং ইভেন্ট হ্যান্ডলার রি-রেন্ডার থেকে "বাঁচিয়ে" থাকে না (কল হবে)। প্রতিটি রেন্ডারের নিজস্ব ইভেন্ট হ্যান্ডলার থাকে।
- প্রতিটি রেন্ডার (এবং এর ভিতরে ফাংশন) সর্বদা রিঅ্যাক্ট যে অবস্থার স্ন্যাপশট দিয়েছে তার আপডেট ভেলু পাবে।
- আপনি মনে মনে ইভেন্ট হ্যান্ডলারগুলিতে স্টেট প্রতিস্থাপন করতে পারেন, এবং রেন্ডার করা JSX সম্পর্কে চিন্তা করে নিতে পারেন।
- অতীতে তৈরি ইভেন্ট হ্যান্ডলারগুলিতে সেই রেন্ডারের স্টেটের মান থাকে।