আপনার হয়তো useEffect-এর দরকার নেই
useEffect
হচ্ছে React-এর নিয়মকানুন (paradigm) থেকে বের হয়ে বাইরের কোনো সিস্টেমের (যেমন: API, DOM, থার্ড-পার্টি লাইব্রেরি) সাথে যোগাযোগ করার দরজা। কিন্তু যদি React কম্পোনেন্টের ভিতরে থাকা props বা state পরিবর্তনের ভিত্তিতে কিছু করার দরকার হয়, তাহলে useEffect
এর প্রয়োজন নেই। অপ্রয়োজনীয় useEffect
ব্যবহার করলে কোড জটিল হয়, পারফরম্যান্স কমে যায়, এবং বাগ হওয়ার ঝুঁকি বাড়ে।
- কখন এবং কেন অপ্রয়োজনীয়
useEffect
বাদ দিতে হবে - কিভাবে খরচসাপেক্ষ (expensive) গণনা Effect ছাড়া ক্যাশ করবেন
- কিভাবে state reset বা আপডেট করবেন
useEffect
ছাড়া - কিভাবে একাধিক ইভেন্ট হ্যান্ডলারে লজিক শেয়ার করবেন
- কোন লজিক ইভেন্ট হ্যান্ডলারে রাখা উচিত
- কিভাবে প্যারেন্ট কম্পোনেন্টকে পরিবর্তনের খবর দেবেন
কিভাবে অপ্রয়োজনীয় useEffect বাদ দিবেন
React-এ দুইটি সাধারণ ক্ষেত্রে useEffect
না লিখেও আপনার কাজ হয়ে যাবে:
✅ আপনি যদি ডাটা ফিল্টার/পরিবর্তন করে দেখাতে চান
ভুল পদ্ধতি (যেখানে অনেকে useEffect
ব্যবহার করে):
const [filteredList, setFilteredList] = useState([]);
useEffect(() => {
setFilteredList(list.filter((item) => item.active));
}, [list]);
ভাল পদ্ধতি (Effect ছাড়া):
const filteredList = list.filter((item) => item.active);
📌 কেন?
React যখন রেন্ডার করে, তখন সে filteredList
আবার হিসাব করে নেয়। আলাদা করে useEffect
দিয়ে state সেট করলে React অতিরিক্ত রেন্ডার করে। তাই শুধু দেখানোর জন্য ফিল্টার করলে, সরাসরি উপরের মতো লিখলেই যথেষ্ট।
✅ আপনি যদি ইউজারের event হ্যান্ডল করতে চান
ভুল পদ্ধতি (Effect দিয়ে event ধরে):
useEffect(() => {
if (hasBought) {
fetch("/api/buy");
alert("Thanks!");
}
}, [hasBought]);
ভাল পদ্ধতি (ইভেন্ট হ্যান্ডলারে সরাসরি কাজ):
function handleBuyClick() {
fetch("/api/buy");
alert("Thanks!");
}
📌 কেন?
ইউজার কখন কি করেছে সেটা আপনি ইভেন্ট হ্যান্ডলারের ভিতরে জানেন। কিন্তু useEffect
তখন চালু হয় যখন কাজ শেষ, অথচ কী হয়েছে সেটা বোঝার উপায় থাকে না। তাই ইভেন্টের কাজ ইভেন্ট হ্যান্ডলারেই করা সবচেয়ে ভালো।
🧪 তাহলে কখন useEffect ব্যবহার করবো?
আপনি যদি বাইরের সিস্টেমের সাথে React state বা UI সিঙ্ক করতে চান, তখন useEffect
দরকার হয়।
উদাহরণ:
useEffect(() => {
const controller = new AbortController();
fetch("/api/products", { signal: controller.signal })
.then((res) => res.json())
.then((data) => setProducts(data));
return () => controller.abort();
}, []);
📌 এটা দরকার হয় যখন:
- API থেকে ডেটা আনতে হয়
- DOM ম্যানিপুলেশন করতে হয়
- WebSocket বা localStorage ব্যবহার করতে হয়
- কোনো থার্ড-পার্টি লাইব্রেরি React এর সাথে যুক্ত করতে হয়
🔚 শেষ কথা:
আপনি কী করতে চান? | useEffect দরকার? |
---|---|
ডাটা সাজানো (filter/sort/map) | ❌ না |
ইউজারের ক্লিক/ইনপুট হ্যান্ডল করা | ❌ না |
API কল / DOM পরিবর্তন / External Widget | ✅ হ্যাঁ |
এখন আপনি বুঝে যাবেন, সব কিছুতেই useEffect
দরকার হয় না। কোড সহজ ও পারফর্মেন্ট রাখতে হলে শুধুমাত্র দরকার হলে useEffect
ব্যবহার করুন।
নিচে আমি আপনার দেওয়া স্টাইল অনুসরণ করে সহজ বাংলায়, টিউটোরিয়াল আকারে অনুবাদ করে দিলাম:
props বা state-এর উপর ভিত্তি করে state আপডেট
ধরুন, আপনার একটি কম্পোনেন্ট আছে যেখানে দুটি state রয়েছে: firstName
এবং lastName
। আপনি এই দুইটি মিলিয়ে fullName
তৈরি করতে চান। আর চাইছেন, যখনই firstName
বা lastName
বদলাবে, fullName
নিজে থেকেই আপডেট হয়ে যাক।
তখন হয়তো আপনি এইভাবে fullName
কে আলাদা state হিসেবে রেখে useEffect
দিয়ে আপডেট করার কথা ভাববেন:
function Form() {
const [firstName, setFirstName] = useState("Taylor");
const [lastName, setLastName] = useState("Swift");
// 🔴 ভুল পদ্ধতি: বাড়তি state এবং অপ্রয়োজনীয় Effect
const [fullName, setFullName] = useState("");
useEffect(() => {
setFullName(firstName + " " + lastName);
}, [firstName, lastName]);
// ...
}
এই পদ্ধতিতে কাজ unnecessary জটিল হয়ে যায়। প্রথমে fullName
পুরনো (stale) মান নিয়ে রেন্ডার হয়, তারপর আবার নতুন মান দিয়ে রেন্ডার হয় — মানে এক্সট্রা রেন্ডারিং!
এর চেয়ে সহজ উপায় হলো: fullName
কে সরাসরি রেন্ডারের সময় হিসাব করা:
function Form() {
const [firstName, setFirstName] = useState("Taylor");
const [lastName, setLastName] = useState("Swift");
// ✅ ভালো পদ্ধতি: সরাসরি রেন্ডারের সময় হিসাব করা
const fullName = firstName + " " + lastName;
// ...
}
📌 যখন কিছু আপনি সহজেই props বা state থেকে হিসাব করতে পারেন, তখন সেটাকে state-এ রাখার দরকার নেই। বরং সরাসরি রেন্ডারের সময় হিসাব করে ফেলুন।
এর ফলে আপনি পাবেন:
- ✅ ভালো পারফরম্যান্স (কারণ বাড়তি রেন্ডার হবে না)
- ✅ কম কোড (বাড়তি state ও
useEffect
বাদ) - ✅ কম বাগ (state গুলোর মধ্যে ভুলভাবে mismatch হওয়ার ঝুঁকি কম)
যদি এই কনসেপ্টটা নতুন লাগে, তাহলে "Thinking in React" (opens in a new tab) গাইডটি দেখলে পরিষ্কার ধারণা পাবেন কোন জিনিসগুলো state-এ রাখা উচিত আর কোনগুলো নয়।
নিচে আমি সহজ ভাষায়, টিউটোরিয়াল স্টাইলে বাংলায় অনুবাদ করলাম:
যখন কোনো prop পরিবর্তিত হয়, তখন কিছু state অ্যাডজাস্ট করা
কখনো কখনো আপনি চাচ্ছেন যে, কোনো prop পরিবর্তিত হলে state-এর কিছু অংশ রিসেট বা পরিবর্তন হোক — কিন্তু পুরোটা নয়।
ধরুন এই List
কম্পোনেন্টটি items
নামের একটি prop নিচ্ছে এবং selection
নামে একটি state রাখছে, যেটা নির্বাচিত আইটেম ট্র্যাক করে। আপনি চাইছেন, যখনই items
নতুন কোনো অ্যারে পায়, তখন selection
যেন null
হয়ে যায়।
আপনি হয়তো এমন কোড লিখতে পারেন:
function List({ items }) {
const [isReverse, setIsReverse] = useState(false);
const [selection, setSelection] = useState(null);
// 🔴 ভুল: prop পরিবর্তনে Effect দিয়ে state আপডেট করা
useEffect(() => {
setSelection(null);
}, [items]);
// ...
}
❌ এই পদ্ধতিও পারফেক্ট নয়। কারণ এখানে যা হচ্ছে:
items
বদলানোর পরList
এবং এর চাইল্ড কম্পোনেন্টগুলো পুরনোselection
দিয়ে রেন্ডার হয়।- তারপর React DOM আপডেট করে এবং
useEffect
চালায়। - এরপর
setSelection(null)
দিয়ে আবার রেন্ডার শুরু হয়।
অর্থাৎ এক্সট্রা এক রেন্ডারিং সাইকেল হয়ে যায়।
✅ এই সমস্যার ভালো সমাধান হলো: useEffect
বাদ দিয়ে রেন্ডারের সময় সরাসরি স্টেট আপডেট করা:
function List({ items }) {
const [isReverse, setIsReverse] = useState(false);
const [selection, setSelection] = useState(null);
// ✅ ভালো: রেন্ডারের সময়ই চেক ও আপডেট
const [prevItems, setPrevItems] = useState(items);
if (items !== prevItems) {
setPrevItems(items);
setSelection(null);
}
// ...
}
এইভাবে আগের রেন্ডারের তথ্য সংরক্ষণ (opens in a new tab) করে স্টেট ম্যানেজ করা একটু কঠিন মনে হতে পারে, কিন্তু useEffect
দিয়ে একই স্টেট আপডেট করার চেয়ে এটা ভালো।
উপরের কোডে, setSelection(null)
সরাসরি রেন্ডারের ভিতরেই হচ্ছে। এর ফলে React অবিলম্বে রেন্ডার রিজেক্ট করে আবার নতুন করে রেন্ডার শুরু করে — কিন্তু এখনো DOM আপডেট করেনি বা চাইল্ড কম্পোনেন্ট রেন্ডার করেনি। ফলে পুরনো selection
দিয়ে DOM-এ কিছু দেখানোর সুযোগই থাকে না।
⚠️ মনে রাখবেন: রেন্ডারের সময় শুধু সেই একই কম্পোনেন্টের স্টেট আপডেট করতে পারবেন। অন্য কম্পোনেন্টের স্টেট আপডেট করতে গেলে React এরর দেখাবে।
🔁 items !== prevItems
এই কন্ডিশনটা ব্যবহার করা জরুরি — না হলে ইনফিনিট লুপে পড়বেন।
⛔ যেকোনো DOM ম্যানিপুলেশন বা টাইমার সেট করার মতো কাজ রেন্ডারের সময় করা যাবে না — সেগুলোর জায়গা হলো useEffect
বা ইভেন্ট হ্যান্ডলার।
✅ সবচেয়ে ভালো সমাধান: স্টেট এডজাস্ট করার দরকারই নেই
যদিও এই প্যাটার্ন useEffect
-এর চেয়ে ভালো, তারপরও বেশিরভাগ ক্ষেত্রে আপনাকে এটা ব্যবহার করতে হবে না। কারণ props বা state-এর উপর ভিত্তি করে স্টেট আপডেট করা মানে হচ্ছে ডেটা ফ্লো আরও জটিল করা, যেটা ডিবাগ করা কষ্টকর।
তাই প্রথমে দেখুন আপনি কি পারতেন:
উদাহরণ:
selection
স্টেট রেখে এবং বারবার রিসেট না করে, বরং selectedId
রেখে সরাসরি রেন্ডারের সময় selection
হিসাব করা যায়:
function List({ items }) {
const [isReverse, setIsReverse] = useState(false);
const [selectedId, setSelectedId] = useState(null);
// ✅ শ্রেষ্ঠ পদ্ধতি: রেন্ডারের সময় হিসাব
const selection = items.find((item) => item.id === selectedId) ?? null;
// ...
}
এখন আর state "reset" করার দরকার নেই। যদি selectedId
-র সাথে মিল থাকা আইটেম items
-এর মধ্যে থাকে, তাহলে সেটা থাকবে নির্বাচিত। আর না থাকলে, selection
হবে null
।
🎯 এই পদ্ধতিতে selection
স্বাভাবিকভাবে আপডেট হয়, এবং আপনি বাড়তি ইফেক্ট বা স্টেট এডজাস্ট করার ঝামেলা থেকে বেঁচে যান।
নিচে আপনার React টিউটোরিয়াল PDF-এর জন্য সহজ ও স্পষ্ট বাংলায় অনুবাদ দিলাম:
POST রিকোয়েস্ট পাঠানো
এই Form
কম্পোনেন্ট দুই ধরনের POST রিকোয়েস্ট পাঠায়।
কম্পোনেন্ট যখন চালু হয় তখন এটা একটি অ্যানালাইটিক্স ইভেন্ট পাঠায়। আর যখন আপনি ফর্ম পূরণ করে Submit বাটনে ক্লিক করবেন, তখন এটা /api/register
এ POST রিকোয়েস্ট পাঠাবে:
function Form() {
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
// ✅ সঠিক: এই কোডটা চলবে কারণ কম্পোনেন্ট দেখানো হয়েছে
useEffect(() => {
post("/analytics/event", { eventName: "visit_form" });
}, []);
// 🔴 ভুল: ইভেন্ট-নির্ভর লজিক useEffect এ রাখা ঠিক না
const [jsonToSubmit, setJsonToSubmit] = useState(null);
useEffect(() => {
if (jsonToSubmit !== null) {
post("/api/register", jsonToSubmit);
}
}, [jsonToSubmit]);
function handleSubmit(e) {
e.preventDefault();
setJsonToSubmit({ firstName, lastName });
}
}
আগের উদাহরণের মতোই এখানে চিন্তা করুন:
অ্যানালাইটিক্স POST রিকোয়েস্টটি useEffect
-এ থাকা উচিত। কারণ এই রিকোয়েস্টটি পাঠানোর কারণ হলো ফর্মটি ইউজারের কাছে দেখানো হয়েছে।
(ডেভেলপমেন্টে এটা দুইবার চালু হতে পারে, সেটা নিয়ে এখানে (opens in a new tab) বিস্তারিত আছে।)
কিন্তু /api/register
POST রিকোয়েস্টটি ফর্ম দেখানোর কারণে নয়।
এটা কেবল তখনই পাঠাতে হবে যখন ব্যবহারকারী Submit বাটন চাপবে। অর্থাৎ, এটা শুধুমাত্র ওই স্পেসিফিক ইন্টারঅ্যাকশনের সময় ঘটবে।
তাই দ্বিতীয় useEffect
মুছে ফেলুন এবং POST রিকোয়েস্টটি সরাসরি ইভেন্ট হ্যান্ডলারে নিয়ে যান:
function Form() {
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
// ✅ সঠিক: এই কোড কম্পোনেন্ট দেখানোর জন্য চলছে
useEffect(() => {
post("/analytics/event", { eventName: "visit_form" });
}, []);
function handleSubmit(e) {
e.preventDefault();
// ✅ সঠিক: ইভেন্ট-নির্ভর লজিক ইভেন্ট হ্যান্ডলারে আছে
post("/api/register", { firstName, lastName });
}
}
কোনো লজিক ইভেন্ট হ্যান্ডলারে রাখবেন নাকি useEffect
-এ —
সেটা ঠিক করার জন্য মূল প্রশ্ন হলো:
এই কোডটা ব্যবহারকারীর দৃষ্টিকোণ থেকে কী কারণে চালানো দরকার?
যদি কোডটা কোনো বিশেষ ইন্টারঅ্যাকশনের জন্য হয়, তাহলে ইভেন্ট হ্যান্ডলারে রাখুন।
আর যদি কোডটা চালাতে হয় কারণ ইউজার কম্পোনেন্টটি স্ক্রিনে দেখেছে, তাহলে useEffect
-এ রাখুন।
অবশ্যই! আরও সহজ ও সরল ভাষায় বোঝাই:
Chains of computations (গণনার ধারা)
React এ কখনো কখনো আপনি এমন কোড লিখতে পারেন যেখানে একটার পর একটা useEffect
থাকে, আর প্রত্যেকটা আগের স্টেট দেখে নিজের স্টেট আপডেট করে। এটা একটা ধারা বা “chain” হয়ে যায়।
উদাহরণ:
- প্রথমে
card
বদলে। - তারপর
goldCardCount
বাড়ে। - তারপর
round
বাড়ে। - তারপর
isGameOver
হয়।
এগুলো একে একে useEffect
চালিয়ে একে অন্যকে ট্রিগার করে।
সমস্যা কী?
-
ধীরগতির কারণ: প্রতিটা
setState
করার পর React আবার পুরো কম্পোনেন্ট ও তার সন্তানদের রি-রেন্ডার করে। ধরুন:setCard
→ রেন্ডারsetGoldCardCount
→ রেন্ডারsetRound
→ রেন্ডারsetIsGameOver
→ রেন্ডার
এই রেন্ডারগুলো অনেক সময় ও শক্তি নষ্ট করে।
-
কোড জটিল ও ভঙ্গুর হয়: যদি ভবিষ্যতে আপনি গেমের আগের খেলার অবস্থা দেখানোর মতো ফিচার করেন, তাহলে পুরানো মান দিয়ে স্টেট আপডেট করলে আবার ঐ
useEffect
গুলো চালু হয়ে ভুল ডেটা দেখাবে। মানে এই ধরনের কোড সহজে বদলানো যায় না, খারাপ কাজ করে।
কী করলে ভালো?
- রান্নার সময় (render) যতটুকু হিসাব করা যায়, করে রাখুন।
- স্টেট আপডেট সব এক জায়গায়, ইভেন্ট হ্যান্ডলারে (যখন ইউজার কাজ করে) করুন।
উদাহরণ:
function Game() {
const [card, setCard] = useState(null);
const [goldCardCount, setGoldCardCount] = useState(0);
const [round, setRound] = useState(1);
// রান্নার সময় হিসাব করুন
const isGameOver = round > 5;
function handlePlaceCard(nextCard) {
if (isGameOver) {
throw Error("Game already ended.");
}
// সব হিসাব এখানে একবারে করুন
setCard(nextCard);
if (nextCard.gold) {
if (goldCardCount <= 3) {
setGoldCardCount(goldCardCount + 1);
} else {
setGoldCardCount(0);
setRound(round + 1);
if (round === 5) {
alert("Good game!");
}
}
}
}
}
এভাবে কোড দ্রুত চলে, কম রি-রেন্ডার হয়, এবং পরবর্তী আপডেট সহজ হয়।
ছোট্ট কিন্তু গুরুত্বপূর্ণ কথা:
-
ইভেন্ট হ্যান্ডলারের মধ্যে
state
আসলে পুরানো মানের একটি snapshot। -
setRound(round + 1)
কল করার পরওround
একই থাকে যতক্ষণ রি-রেন্ডার হয় না। -
নতুন মান দরকার হলে নিজে একটা নতুন ভেরিয়েবল বানাতে হবে, যেমন:
const nextRound = round + 1;
কখনও কখনও চেইন করা ঠিক থাকে:
যেমন, ফর্মে অনেক ড্রপডাউন আছে যেখানে পরের ড্রপডাউনের অপশন আগের ড্রপডাউনের সিলেকশনের উপর নির্ভর করে।
এক্ষেত্রে নেটওয়ার্ক থেকে ডেটা আনতে হলে useEffect
দিয়ে ধাপে ধাপে আপডেট করতে হয়।
সারমর্ম:
একের পর এক
useEffect
দিয়ে স্টেট পরিবর্তন করলে কোড ধীর ও জটিল হয়। স্টেট পরিবর্তন সম্ভব হলে ইভেন্ট হ্যান্ডলারে একবারেই সব করুন। এতে কোড দ্রুত ও সহজ হয়।
নিশ্চিতভাবেই! নিচে আমি সরল ভাষায়, সহজ শব্দে ব্যাখ্যা করেছি — যেন React শেখা নতুনদের জন্যও বুঝতে সুবিধা হয়। প্রতিটি পয়েন্টের সাথে সম্পূর্ণ কোডসহ উদাহরণ দিয়েছি, যাতে পাঠক বুঝতে পারেন কী হচ্ছে এবং কেন হচ্ছে।
🔰 অ্যাপ শুরু হওয়ার সময় (Initialization) যা একবারই চালানো উচিত
অনেক সময় আমাদের কিছু কাজ অ্যাপ লোড হওয়ার সময় শুধু একবারই চালানো দরকার হয়। যেমন:
- LocalStorage থেকে ডেটা লোড করা
- ইউজারের লগইন টোকেন চেক করা
তুমি হয়তো ভাবতে পারো, এই কাজগুলো useEffect
দিয়ে করা যায়, যেমন:
import { useEffect } from "react";
function App() {
// ⚠️ ভুল পদ্ধতি: এটা দুইবার চলতে পারে ডেভেলপমেন্টে
useEffect(() => {
loadDataFromLocalStorage();
checkAuthToken();
}, []);
return <h1>Hello App</h1>;
}
function loadDataFromLocalStorage() {
console.log("📦 LocalStorage থেকে ডেটা লোড হলো");
}
function checkAuthToken() {
console.log("🔐 টোকেন চেক করা হলো");
}
⚠️ সমস্যাটা কী?
React এর Strict Mode (ডেভেলপমেন্ট মোডে) useEffect()
দুইবার কল করে যেন তুমি বুঝতে পারো তোমার কোড “বারবার চলে গেলে” ঠিকভাবে কাজ করবে কিনা।
তাই, উপরের কোডে checkAuthToken()
এবং loadDataFromLocalStorage()
দুইবার চলবে। এতে সমস্যা হতে পারে, যেমন:
- টোকেন এক্সপায়ার হয়ে যেতে পারে
- ডেটা ভুল হয়ে যেতে পারে
✅ সমাধান ১: ভ্যারিয়েবল দিয়ে কন্ট্রোল করা
আমরা চাই এই কোড পুরো অ্যাপ চালু হলে একবারই চলুক, বারবার না। এজন্য একটা টপ-লেভেল ভ্যারিয়েবল দিয়ে কন্ট্রোল করা যায়:
import { useEffect } from "react";
// এই ভ্যারিয়েবলটা টপ-লেভেলে থাকবে
let didInit = false;
function App() {
useEffect(() => {
if (!didInit) {
didInit = true; // একবার চালানোর পর true করে দিচ্ছি
loadDataFromLocalStorage();
checkAuthToken();
}
}, []);
return <h1>✅ সঠিকভাবে একবার চালানো হয়েছে</h1>;
}
function loadDataFromLocalStorage() {
console.log("📦 LocalStorage থেকে ডেটা লোড হলো");
}
function checkAuthToken() {
console.log("🔐 টোকেন চেক করা হলো");
}
⛑️ এটা কিভাবে কাজ করে?
didInit
নামে একটা ভ্যারিয়েবল বাইরে declare করা হয়েছে।- যখন
App
চলে, তখনuseEffect
এর ভেতর চেক করা হয় —didInit
যদি false হয়, তাহলে কোড চলবে। - একবার চলার পর
didInit = true
করে দেয়া হয়, তাই আর দ্বিতীয়বার চলে না।
✅ সমাধান ২: রেন্ডার হওয়ার আগেই চালানো (module initialization)
তুমি চাইলে App
কম্পোনেন্ট রেন্ডার হওয়ার আগেই — অর্থাৎ ফাইল ইম্পোর্ট হওয়ার সময় — কিছু কোড একবারই চালাতে পারো:
// চেক করে নিচ্ছি যেন শুধু ব্রাউজারে চলুক
if (typeof window !== "undefined") {
checkAuthToken();
loadDataFromLocalStorage();
}
function App() {
return <h1>🌐 আগে থেকেই ইনিশিয়ালাইজ করা হয়েছে</h1>;
}
function loadDataFromLocalStorage() {
console.log("📦 LocalStorage থেকে ডেটা লোড হলো");
}
function checkAuthToken() {
console.log("🔐 টোকেন চেক করা হলো");
}
⚠️ সাবধানতা:
এই প্যাটার্ন সব জায়গায় ব্যবহার করলে সমস্যা হতে পারে। কারণ:
- যখনই এই ফাইল
import
হবে, তখনই কোড চালবে—even যদি কম্পোনেন্ট রেন্ডারই না হয়! - এতে performance কমে যেতে পারে, বিশেষ করে বড় অ্যাপে।
তাই এই প্যাটার্ন শুধু App.js
বা অ্যাপের entry point-এ ব্যবহার করো।
🧠 মনে রাখার বিষয়গুলো:
বিষয় | কারণ |
---|---|
useEffect() দিয়ে একবার চালাতে চাইলে didInit ব্যবহার করো | Strict mode-এ useEffect() দুইবার চলে |
ফাইল ইম্পোর্ট হওয়ার সময় চালাতে চাইলে উপরে if (typeof window !== 'undefined') দিয়ে চালাও | যাতে শুধু ব্রাউজারে চলে, সার্ভারে না |
কোড সহজ ও পরিষ্কার রাখতে এই লজিক শুধু App.js বা main entry point-এ রাখো | যেন অন্য কম্পোনেন্টে অপ্রয়োজনীয় execution না হয় |
তুমি চাইলে আমি এই অংশটাকে সুন্দরভাবে PDF-ready ডিজাইনে তৈরি করে দিতে পারি, কিংবা React Bangla বইয়ের অধ্যায়ে যুক্ত করে দিতে পারি।
অবশ্যই, নিচে তোমার দেওয়া টেক্সটের বাংলা অনুবাদ + অতিরিক্ত ব্যাখ্যা + বাস্তব জীবনের একটি সম্পূর্ণ ফিচার ভিত্তিক উদাহরণ দেওয়া হলো যেন তুমি সহজেই বুঝতে পারো।
🔁 বিষয়: Parent Component কে State Update সম্পর্কে জানানো
🧠 ধরো তুমি একটি Toggle কম্পোনেন্ট বানাচ্ছো।
এই কম্পোনেন্টে isOn
নামে একটি state
আছে যা true
বা false
হতে পারে। অর্থাৎ টগল অন আছে না অফ আছে সেটা ধরে রাখে।
এই Toggle
কম্পোনেন্টে দুইভাবে টগল করা যায়:
- ক্লিক করে
- ড্র্যাগ করে
তুমি চাও যখনই এই isOn
স্টেট চেঞ্জ হবে, তখন যেন প্যারেন্ট কম্পোনেন্টকে জানানো হয়। এজন্য তুমি onChange
নামে একটি ফাংশন প্যারেন্ট থেকে রিসিভ করে, সেটা useEffect
এর মাধ্যমে কল করছো।
❌ ভুল পদ্ধতি (যা করা উচিত না)
useEffect(() => {
onChange(isOn);
}, [isOn, onChange]);
এখানে সমস্যা হলো:
- তুমি প্রথমে
setIsOn()
দিয়ে টগল কম্পোনেন্টের স্টেট আপডেট করছো - তারপর React DOM আপডেট করে
- তারপর
useEffect
চলবে, তখনonChange()
কল হবে - তখন প্যারেন্টের স্টেট আবার আপডেট হবে এবং নতুনভাবে রেন্ডার হবে
👉 ফলে দুইবার রেন্ডার হয়, যা পারফরম্যান্সের জন্য খারাপ এবং কোডও অপ্রয়োজনীয় জটিল হয়ে যায়।
✅ সঠিক পদ্ধতি: সবকিছু একই ইভেন্ট হ্যান্ডলারে করো
function updateToggle(nextIsOn) {
setIsOn(nextIsOn);
onChange(nextIsOn);
}
এভাবে setIsOn()
আর onChange()
একসাথে কল করো ক্লিক বা ড্র্যাগ ইভেন্টে।
✅ আরও ভালো পদ্ধতি: প্যারেন্টের কাছে পুরো স্টেট তুলে দাও (lifting state up)
function Toggle({ isOn, onChange }) {
function handleClick() {
onChange(!isOn);
}
function handleDragEnd(e) {
if (isCloserToRightEdge(e)) {
onChange(true);
} else {
onChange(false);
}
}
}
এখানে Toggle
কম্পোনেন্ট নিজের কোনো স্টেট রাখে না। পুরো স্টেট প্যারেন্ট কম্পোনেন্ট মেইনটেইন করে, যাকে বলে "lifting state up". এতে টগল কম্পোনেন্টটা পুরোপুরি কন্ট্রোলড হয়ে যায়।
🔦 বাস্তব উদাহরণ: ফোনের ফ্ল্যাশলাইট অন/অফ
🔧 ফিচার লিস্ট:
- একটি
Toggle
কম্পোনেন্ট থাকবে (সুইচের মতো) - ইউজার ক্লিক করলে ফ্ল্যাশলাইট চালু/বন্ধ হবে
- ইউজার ড্র্যাগ করে ছেড়ে দিলে, বাম/ডান দেখে ফ্ল্যাশলাইট চালু/বন্ধ হবে
- প্যারেন্ট কম্পোনেন্ট জানবে ফ্ল্যাশলাইট চালু আছে কিনা
- যদি চাও,
Toggle
কম্পোনেন্ট স্টেট রাখবে - না চাইলে সব স্টেট প্যারেন্টেই থাকবে
✅ কোড (lifting state up approach):
// Toggle.js
function Toggle({ isOn, onChange }) {
function isCloserToRightEdge(e) {
return e.clientX > window.innerWidth / 2;
}
function handleClick() {
onChange(!isOn);
}
function handleDragEnd(e) {
if (isCloserToRightEdge(e)) {
onChange(true);
} else {
onChange(false);
}
}
return (
<div
draggable
onClick={handleClick}
onDragEnd={handleDragEnd}
className={`w-24 h-12 flex items-center rounded-full
${isOn ? "bg-green-500" : "bg-gray-400"}`}
>
<div
className={`w-10 h-10 rounded-full bg-white shadow-md transition-transform duration-300
${isOn ? "translate-x-6" : "translate-x-0"}`}
/>
</div>
);
}
// App.js (Parent component)
import { useState } from "react";
import Toggle from "./Toggle";
export default function App() {
const [flashOn, setFlashOn] = useState(false);
return (
<div className="min-h-screen flex flex-col items-center justify-center gap-4">
<Toggle isOn={flashOn} onChange={setFlashOn} />
<p className="text-xl font-bold">
Flashlight is {flashOn ? "ON 🔦" : "OFF 🌑"}
</p>
</div>
);
}
🧾 সারাংশ:
কৌশল | সুবিধা |
---|---|
useEffect দিয়ে onChange কল | ❌ ধীর, দুটি রেন্ডার, ভুল ধরতে কঠিন |
একই ইভেন্টে setState এবং onChange | ✅ দ্রুত, একটি রেন্ডার |
lifting state up (stateless child) | ✅ সিম্পল, সিঙ্ক সমস্যা নেই, রিইউজযোগ্য |
🏦
হিসাব নাম:
হিসাব নম্বর:
📲 (Personal):
💰 :
🔸 BTC (BNB Smart Chain):
🔸 Litecoin:
🔸 Bitcoin: