State হলো Flutter-এর কেন্দ্রীয় ডেটা ব্যবস্থাপনা অবজেক্ট, যা StatefulWidget-এর সাথে যুক্ত এবং পরিবর্তনযোগ্য তথ্য সংরক্ষণ ও ইন্টারফেস তৈরির জন্য দায়ী। অফিসিয়াল Flutter ডকুমেন্টেশন (Flutter.dev, 2026) অনুযায়ী, State উইজেটের পুরো জীবনচক্র জুড়ে বিদ্যমান থাকে এবং এর পুনর্নির্মাণ থেকে বেঁচে যায়, UI আপডেটের মধ্যে ডেটা সামঞ্জস্য নিশ্চিত করে। উইজেটের নিজের বিপরীতে, State তার ফিল্ডগুলি পরিবর্তন করতে পারে এবং setState কলের মাধ্যমে পুনর্নির্মাণ শুরু করতে পারে।
মূল বিষয়
State হলো Flutter আর্কিটেকচারের একটি অবজেক্ট যা StatefulWidget-এর পরিবর্তনযোগ্য ডেটা সংরক্ষণ করে এবং নির্ধারণ করে কিভাবে এই ডেটা ইন্টারফেসে প্রদর্শিত হয়। প্রতিটি StatefulWidget, ট্রিতে স্থাপিত হলে, createState মেথডের মাধ্যমে ঠিক একটি State অবজেক্ট তৈরি করে। State উইজেট থেকে স্বাধীনভাবে বিদ্যমান থাকে: যদি প্যারেন্ট নতুন প্যারামিটার সহ StatefulWidget পুনর্নির্মাণ করে, State একই থাকে এবং widget প্রপার্টির মাধ্যমে আপডেটেড উইজেট গ্রহণ করে।
Flutter আর্কিটেকচারাল ওভারভিউ (Google, 2026) অনুযায়ী, Widget এবং State-এর পৃথকীকরণ একটি সচেতন আর্কিটেকচারাল সিদ্ধান্ত যা ফ্রেমওয়ার্ককে ট্রি এলিমেন্ট পুনরায় ব্যবহার করতে দেয়। উইজেট (একটি হালকা বর্ণনা) একাধিকবার তৈরি এবং ধ্বংস করা যেতে পারে, কিন্তু State (ডেটাসহ একটি ভারী অবজেক্ট) মেমরিতে থাকে যতক্ষণ এলিমেন্ট ট্রিতে থাকে। এটি প্যারেন্ট উইজেটের ঘন ঘন পুনর্নির্মাণের সময় ডেটা ক্ষতি রোধ করে।
State জেনেরিকের মাধ্যমে StatefulWidget ইন্টারফেস বাস্তবায়ন করে: class _MyState extends State<MyWidget>। জেনেরিক State-কে একটি নির্দিষ্ট StatefulWidget প্রকারের সাথে বাঁধে, যা widget প্রপার্টির মাধ্যমে তার ফিল্ডগুলিতে টাইপ-নিরাপদ অ্যাক্সেস প্রদান করে।
State অবজেক্ট StatefulElement-এ সংরক্ষিত হয় — Widget এবং RenderObject-এর মধ্যে একটি মধ্যবর্তী স্তর। StatefulElement createState-এর মাধ্যমে State তৈরি করে, এটির একটি রেফারেন্স রাখে এবং State-কে মালিক হিসাবে পাস করে। Element কেবল তখনই ধ্বংস হয় যখন উইজেট ট্রি থেকে সরানো হয় — ততক্ষণ পর্যন্ত, State মেমরিতে থাকে।
State-এর জীবনচক্র নির্ধারিত এবং কঠোর ক্রমে কলের সমন্বয়ে গঠিত। এই ক্রম বোঝা সঠিক সম্পদ ব্যবস্থাপনা এবং মেমরি লিক প্রতিরোধের ভিত্তি।
initState State তৈরি হলে প্রথমে কল করা হয়। এই মেথডে, কন্ট্রোলার, স্ট্রিম সাবস্ক্রিপশন, টাইমার এবং ফিল্ডের প্রাথমিক মান আরম্ভ করা হয়। প্রথম লাইনে super.initState() কল করা বাধ্যতামূলক। initState ধাপে, উইজেট ট্রি এখনও সম্পূর্ণরূপে মাউন্ট হয়নি, তাই MediaQuery.of(context)-এর মতো মেথড সঠিকভাবে কাজ নাও করতে পারে।
didChangeDependencies initState-এর পরে এবং InheritedWidget নির্ভরতা পরিবর্তিত হলে কল করা হয়। এখানে, initState-এ নয়, MediaQuery.of(context) বা Theme.of(context) কল করা উচিত, কারণ ততক্ষণে ট্রি ইতিমধ্যে মাউন্ট হয়েছে। এই মেথডটি কল করা হয় যদি উইজেট ভিন্ন প্রসঙ্গে চলে যায় যেখানে InheritedWidget অন্যান্য মান প্রদান করে।
build হলো State-এর প্রধান মেথড যা উইজেট ট্রি ফেরত দেয়। এটি initState-এর পরে, didChangeDependencies-এর পরে এবং প্রতিটি setState-এর পরে কল করা হয়। build মেথডের কোনও পার্শ্ব প্রতিক্রিয়া থাকা উচিত নয় — এটি কেবল State ফিল্ডের বর্তমান মানের উপর ভিত্তি করে ইন্টারফেস বর্ণনা করে।
didUpdateWidget কল করা হয় যখন প্যারেন্ট নতুন প্যারামিটার সহ StatefulWidget পুনর্নির্মাণ করে। State পুরানো উইজেটে oldWidget-এর মাধ্যমে অ্যাক্সেস পায় এবং এটি নতুনটির সাথে তুলনা করতে পারে। যদি প্যারামিটার পরিবর্তিত হয়, তাহলে অবস্থা আপডেট করা, নতুন ডেটা লোড করা বা অ্যানিমেশন পুনরায় শুরু করা যেতে পারে।
dispose চূড়ান্ত মেথড যেখানে সমস্ত সম্পদ মুক্ত করা হয়: কন্ট্রোলার, সাবস্ক্রিপশন, টাইমার। dispose-এর পরে, State-কে মৃত হিসাবে চিহ্নিত করা হয়: mounted false ফেরত দেয়, setState কল করলে ব্যতিক্রম উৎপন্ন হয়। মেথডের শেষ লাইনে super.dispose() কল করা বাধ্যতামূলক।
| মেথড | কখন কল করা হয় | বাধ্যতামূলক super |
|---|---|---|
| initState | State তৈরি হলে | হ্যাঁ, প্রথম লাইনে |
| didChangeDependencies | initState-এর পরে এবং InheritedWidget পরিবর্তিত হলে | হ্যাঁ |
| build | initState, didChangeDependencies, setState-এর পরে | না |
| didUpdateWidget | প্যারেন্ট থেকে নতুন উইজেট এলে | হ্যাঁ |
| setState | ডেভেলপার কল করলে | না |
| dispose | ট্রি থেকে সরানো হলে | হ্যাঁ, শেষ লাইনে |
State-এর কার্যপ্রণালী তিনটি মূল নীতির উপর ভিত্তি করে: Element-এর সাথে সংযোগ, setState-এর মাধ্যমে প্রতিক্রিয়াশীলতা এবং widget প্রপার্টির মাধ্যমে প্যারেন্ট অ্যাক্সেস। যখন Flutter এলিমেন্ট ট্রি তৈরি করে এবং StatefulElement-এর সম্মুখীন হয়, তখন এটি সংযুক্ত উইজেটের createState কল করে। তৈরি State এলিমেন্টে সংরক্ষিত হয় এবং যতক্ষণ এলিমেন্ট সরানো না হয় ততক্ষণ বিদ্যমান থাকে।
যখন setState কল করা হয়, State নিজেকে নোংরা হিসাবে চিহ্নিত করে এবং পরবর্তী ফ্রেমের জন্য পুনর্নির্মাণ নির্ধারণ করে। গুরুত্বপূর্ণ: setState অবিলম্বে build কল করে না — এটি কেবল পুনর্নির্মাণের প্রয়োজনীয়তা নিবন্ধন করে। Flutter বর্তমান ফ্রেমের সমস্ত নোংরা এলিমেন্ট সংগ্রহ করে এবং সেগুলিকে ব্যাচে পুনর্নির্মাণ করে, যা কর্মক্ষমতা অপ্টিমাইজ করে। build কল করার পরে, State পরিষ্কার অবস্থায় ফিরে আসে।
widget প্রপার্টি State-কে StatefulWidget কনস্ট্রাক্টরে পাস করা প্যারামিটার পড়তে দেয়। যেহেতু StatefulWidget অপরিবর্তনীয় (StatelessWidget-এর মতো), এর ফিল্ডগুলি পরিবর্তিত হয় না — যখন প্যারামিটার পরিবর্তিত হয়, প্যারেন্ট একটি নতুন উইজেট তৈরি করে, এবং State এটি didUpdateWidget-এর মাধ্যমে গ্রহণ করে। এটি নিশ্চিত করে যে State সর্বদা বর্তমান প্যারেন্ট ডেটার সাথে কাজ করে।
টাইমার দ্বারা পরিবর্তিত ফিল্ড সহ State-এর মৌলিক উদাহরণ। initState, setState এবং dispose প্রদর্শন করে:
class _TimerWidgetState extends State<TimerWidget> {
int _seconds = 0;
Timer? _timer;
@override
void initState() {
super.initState();
_timer = Timer.periodic(
const Duration(seconds: 1),
(_) => setState(() => _seconds++),
);
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Text('$_seconds seconds elapsed');
}
}
প্যারেন্ট প্যারামিটার অ্যাক্সেস করতে এবং didUpdateWidget-এর মাধ্যমে তাদের পরিবর্তনে প্রতিক্রিয়া জানাতে widget প্রপার্টি ব্যবহারের উদাহরণ:
class _GreetingState extends State<GreetingWidget> {
String _displayName = '';
@override
void initState() {
super.initState();
_displayName = _formatName(widget.name);
}
@override
void didUpdateWidget(GreetingWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.name != oldWidget.name) {
setState(() {
_displayName = _formatName(widget.name);
});
}
}
String _formatName(String name) => name.trim().isEmpty ? 'Guest' : name;
@override
Widget build(BuildContext context) {
return Text('Hello, $_displayName!');
}
}
দ্বিতীয় উদাহরণে, State ইনপুট প্যারামিটার name-এর পরিবর্তন ট্র্যাক করে এবং শুধুমাত্র প্রকৃত পরিবর্তন হলে প্রদর্শন পুনরায় বিন্যাস করে। widget.name != oldWidget.name চেক ছাড়া, মেথডটি প্রতিটি প্যারেন্ট পুনর্নির্মাণে কল হতো, এমনকি নাম পরিবর্তন না হলেও — ফ্রেমওয়ার্কের জন্য অপ্রয়োজনীয় কাজ।
State এবং StatefulWidget Flutter আর্কিটেকচারের দুটি ভিন্ন ক্লাস যা ভিন্ন ভূমিকা পালন করে। StatefulWidget একটি হালকা অপরিবর্তনীয় আবরণ যা উইজেট কনফিগারেশন বর্ণনা করে এবং State তৈরি করে। State একটি ভারী অবজেক্ট যা পরিবর্তনযোগ্য ডেটা সংরক্ষণ করে, সাবস্ক্রিপশন পরিচালনা করে এবং UI তৈরি করে। এই পৃথকীকরণ Flutter-কে অবস্থা না হারিয়ে উইজেট তৈরি এবং ধ্বংস করতে দেয়।
StatefulWidget-এর সমস্ত ফিল্ড final হতে হবে এবং কনস্ট্রাক্টরে সেট করতে হবে — এগুলি তৈরির পরে পরিবর্তিত হয় না। State, অন্যদিকে, যেকোনো সময় তার ফিল্ড পরিবর্তন করতে পারে, কিন্তু সমস্ত পরিবর্তনের আগে setState কল করতে হবে যাতে Flutter পুনর্নির্মাণের প্রয়োজনীয়তা সম্পর্কে জানতে পারে। এটি মূল পার্থক্য: StatefulWidget হলো “কী দেখাতে হবে”, State হলো “কীভাবে দেখাতে হবে এবং কী ডেটা ব্যবহার করতে হবে”।
Flutter সোর্স কোড বিশ্লেষণ (Flutter SDK, 2026) অনুযায়ী, StatefulWidget-এ কেবল একটি বাধ্যতামূলক ফিল্ড রয়েছে — createState, যেখানে State-এর BuildContext-এ অ্যাক্সেস আছে, স্ট্রিমে সাবস্ক্রাইব করতে পারে, অ্যানিমেশন এবং কন্ট্রোলার পরিচালনা করতে পারে। StatefulWidget-কে যতটা সম্ভব সরল রাখার, সমস্ত যুক্তি State-তে স্থানান্তর করার পরামর্শ দেওয়া হয়।
Widget এবং State-এর পৃথকীকরণ একটি আর্কিটেকচারাল সিদ্ধান্ত যা কনফিগারেশনের অপরিবর্তনীয়তা নিশ্চিত করে। যদি StatefulWidget নিজেই অবস্থা সংরক্ষণ করত, তাহলে প্রতিটি প্যারেন্ট পুনর্নির্মাণে অবস্থা হারিয়ে যেত। অবস্থাকে একটি পৃথক অবজেক্টে সরিয়ে, Flutter নিশ্চিত করে যে ডেটা পুনর্নির্মাণ থেকে বেঁচে যায়, যখন উইজেট হালকা এবং তুলনাযোগ্য থাকে।
State অবজেক্ট বিচ্ছিন্ন — অন্যান্য উইজেটের State-তে এর সরাসরি অ্যাক্সেস নেই। উইজেটগুলির মধ্যে ডেটা বিনিময়ের জন্য InheritedWidget বা বাহ্যিক অবস্থা ব্যবস্থাপনা টুল ব্যবহার করা হয়: Provider, Riverpod, Bloc, Redux। প্রতিটি পদ্ধতি সমস্যাটি ভিন্নভাবে সমাধান করে: InheritedWidget উইজেট ট্রির মাধ্যমে কাজ করে, Provider DI কন্টেইনারের মাধ্যমে, Bloc ইভেন্ট স্ট্রিমের মাধ্যমে।
টুলের পছন্দ প্রকল্পের স্কেলের উপর নির্ভর করে। ছোট অ্যাপ্লিকেশনের জন্য, InheritedWidget এবং স্থানীয় State যথেষ্ট। মাঝারি এবং বড় প্রকল্পের জন্য, Riverpod বা Bloc সুপারিশ করা হয় — তারা পরীক্ষণযোগ্যতা, পূর্বাভাসযোগ্যতা এবং UI থেকে যুক্তির পৃথকীকরণ নিশ্চিত করে। State তখন কেবল স্থানীয় উইজেট ডেটার (ফোকাস, স্ক্রোল, অ্যানিমেশন) জন্য ব্যবহৃত হয়।
Flutter কমিউনিটি সার্ভে 2025 (Flutter Foundation, ডিসেম্বর 2025) অনুযায়ী, Riverpod নতুন প্রকল্পে সবচেয়ে জনপ্রিয় অবস্থা ব্যবস্থাপনা সমাধান (38%), তারপরে Bloc (31%) এবং Provider (22%)। তিনটি টুলই State-এর সাথে সামঞ্জস্যপূর্ণ এবং মানক জীবনচক্র ত্যাগ করার প্রয়োজন নেই।
প্রথম ভুল হলো অ্যাসিঙ্ক্রোনাস কলব্যাকে setState-এর আগে mounted চেক করতে ভুলে যাওয়া। যখন উইজেট ট্রি থেকে সরানো হয় (উদাহরণস্বরূপ, ব্যবহারকারী স্ক্রিন ছেড়ে চলে গেছে), কিন্তু একটি অ্যাসিঙ্ক্রোনাস অপারেশন (HTTP অনুরোধ) এখনও চলছে, এটি সম্পূর্ণ হওয়ার পরে State ইতিমধ্যে মৃত। মৃত State-এ setState কল করলে ব্যতিক্রম উৎপন্ন হয়। চেক if (mounted) setState(...) সমস্যা সমাধান করে।
দ্বিতীয় ভুল হলো didChangeDependencies-এর পরিবর্তে initState-এ InheritedWidget নির্ভরতা আরম্ভ করা। initState-এ, প্রসঙ্গ এখনও মাউন্ট হয়নি, তাই MediaQuery.of(context) ব্যতিক্রম উৎপন্ন করবে। সমস্ত InheritedWidget নির্ভরতা didChangeDependencies বা build-এ সেট করা উচিত।
তৃতীয় ভুল হলো setState কল না করে ফিল্ড পরিবর্তন করা। যদি ডেভেলপার setState ছাড়া State ফিল্ড পরিবর্তন করে, Flutter পরিবর্তন সম্পর্কে জানতে পারবে না এবং UI আপডেট হবে না। উদাহরণস্বরূপ: পরবর্তী setState((){}) ছাড়া _list.add(item) তালিকা পরিবর্তন করবে, কিন্তু স্ক্রিন একই থাকবে।
State-এ অ্যাসিঙ্ক্রোনাস অপারেশনের জন্য নিরাপত্তা প্যাটার্ন:
Future<void> _fetchData() async {
final data = await ApiService.fetch();
if (mounted) {
setState(() => _data = data);
}
}
mounted চেক নিশ্চিত করে যে setState কেবল জীবিত State-এ কল করা হয়, যা “setState called after dispose” ব্যতিক্রম প্রতিরোধ করে।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
StatefulWidget একটি অপরিবর্তনীয় উইজেট কনফিগারেশন, যেখানে State একটি পরিবর্তনযোগ্য অবজেক্ট যা ডেটা সংরক্ষণ করে এবং জীবনচক্র পরিচালনা করে। উইজেট পুনরায় তৈরি করা যেতে পারে, State পারে না। StatefulWidget createState-এর মাধ্যমে State তৈরি করে।
ঠিক একটি। createState মেথড একবার কল করা হয় যখন StatefulWidget প্রথমবার ট্রিতে স্থাপিত হয়। এমনকি যদি প্যারেন্ট একাধিকবার পুনর্নির্মাণ করে, State অবজেক্ট একই থাকে যতক্ষণ না উইজেটের প্রকার বা Key পরিবর্তিত হয়।
mounted একটি বুলিয়ান ফ্ল্যাগ যা দেখায় যে State উইজেট ট্রিতে আছে কিনা। dispose কল করার পরে, mounted false হয়। ব্যতিক্রম এড়াতে অ্যাসিঙ্ক্রোনাস কলব্যাকে setState-এর আগে চেক করার জন্য ব্যবহৃত হয়।
না। State সর্বদা জেনেরিকের মাধ্যমে একটি নির্দিষ্ট StatefulWidget-এর সাথে আবদ্ধ: State<T extends StatefulWidget>। উইজেটের সাথে সংযোগ ছাড়া সরাসরি State তৈরি করা আর্কিটেকচারালি অসম্ভব।
একটি ব্যতিক্রম উৎপন্ন হয়: “setState called after dispose”। dispose-এর পরে, State মৃত বিবেচিত হয়, এবং setState-এর মাধ্যমে UI পুনর্নির্মাণের যে কোনও প্রচেষ্টা নিষিদ্ধ। সমাধান হলো প্রতিটি setState-এর আগে mounted চেক করা।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন