State: Τι είναι, διαχείριση κατάστασης και αρχή λειτουργίας

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-07-01 Χρόνος ανάγνωσης: 9 λεπ

State — το κεντρικό αντικείμενο διαχείρισης δεδομένων στο Flutter, συνδεδεμένο με το StatefulWidget και υπεύθυνο για την αποθήκευση μεταβαλλόμενων πληροφοριών και τη δημιουργία του περιβάλλοντος διεπαφής. Σύμφωνα με την επίσημη τεκμηρίωση του Flutter (Flutter.dev, 2026), το State υπάρχει καθ' όλη τη διάρκεια ζωής του widget και επιβιώνει από τις ανακατασκευές του, διασφαλίζοντας τη συνέπεια των δεδομένων μεταξύ των ενημερώσεων του UI. Σε αντίθεση με το ίδιο το widget, το State μπορεί να αλλάζει τα πεδία του και να προκαλεί ανακατασκευή μέσω της κλήσης setState.

Κύρια σημεία

  • State — αντικείμενο που αποθηκεύει μεταβαλλόμενα δεδομένα του StatefulWidget και διαχειρίζεται την ανακατασκευή του μέσω setState
  • Κύκλος ζωής — το State περνά από initState, didChangeDependencies, build, didUpdateWidget και dispose, κάθε στάδιο με σαφή σκοπό
  • mounted — σημαία που υποδεικνύει ότι το State βρίσκεται ακόμα στο δέντρο widget και μπορεί να καλέσει με ασφάλεια το setState
  • widget — αναφορά στο συνδεδεμένο StatefulWidget, προσβάσιμη μέσω της ιδιότητας State για ανάγνωση παραμέτρων του γονέα
  • Απομόνωση — το State είναι απομονωμένο από άλλα State· για ανταλλαγή δεδομένων χρησιμοποιούνται InheritedWidget ή εξωτερικά εργαλεία διαχείρισης κατάστασης

Τι είναι το State στο Flutter;

State — είναι ένα αντικείμενο στην αρχιτεκτονική Flutter που αποθηκεύει μεταβαλλόμενα δεδομένα του StatefulWidget και καθορίζει πώς αυτά τα δεδομένα εμφανίζονται στη διεπαφή. Κάθε StatefulWidget κατά την ενσωμάτωση στο δέντρο δημιουργεί ακριβώς ένα αντικείμενο State μέσω της μεθόδου createState. Το State υπάρχει ανεξάρτητα από το widget: εάν ο γονέας ανακατασκευάσει το StatefulWidget με νέες παραμέτρους, το State παραμένει το ίδιο και λαμβάνει το ενημερωμένο widget μέσω της ιδιότητας widget.

Σύμφωνα με το Flutter Architectural Overview (Google, 2026), ο διαχωρισμός Widget και State είναι μια συνειδητή αρχιτεκτονική απόφαση που επιτρέπει στο framework να επαναχρησιμοποιεί στοιχεία του δέντρου. Το widget (ελαφριά περιγραφή) μπορεί να δημιουργηθεί και να καταστραφεί πολλές φορές, αλλά το State (βαρύ αντικείμενο με δεδομένα) παραμένει στη μνήμη όσο το στοιχείο βρίσκεται στο δέντρο. Αυτό αποτρέπει την απώλεια δεδομένων κατά τις συχνές ανακατασκευές των γονικών widget.

Το State υλοποιεί τη διεπαφή StatefulWidget μέσω generics: class _MyState extends State<MyWidget>. Το generic συνδέει το State με συγκεκριμένο τύπο StatefulWidget, διασφαλίζοντας type-safe πρόσβαση στα πεδία του μέσω της ιδιότητας widget.

Πού αποθηκεύεται το State;

Το αντικείμενο State αποθηκεύεται στο StatefulElement — το ενδιάμεσο επίπεδο μεταξύ Widget και RenderObject. Το StatefulElement δημιουργεί το State μέσω createState, διατηρεί αναφορά σε αυτό και μεταβιβάζει το State ως κάτοχο. Το Element καταστρέφεται μόνο όταν το widget αφαιρεθεί από το δέντρο — μέχρι τότε το State ζει στη μνήμη.

Κύκλος ζωής του State

Ο κύκλος ζωής του State είναι ντετερμινιστικός και αποτελείται από μια αυστηρή ακολουθία κλήσεων. Η κατανόηση αυτής της ακολουθίας είναι το θεμέλιο για τη σωστή διαχείριση πόρων και την πρόληψη διαρροών μνήμης.

initState — αρχικοποίηση

Το initState καλείται πρώτο κατά τη δημιουργία του State. Σε αυτή τη μέθοδο αρχικοποιούνται οι ελεγκτές, οι συνδρομές σε ροές δεδομένων, τα χρονόμετρα και οι αρχικές τιμές πεδίων. Είναι υποχρεωτική η κλήση super.initState() στην πρώτη γραμμή. Στο στάδιο initState το δέντρο widget δεν έχει ακόμα πλήρως τοποθετηθεί, επομένως μέθοδοι όπως MediaQuery.of(context) μπορεί να λειτουργήσουν εσφαλμένα.

didChangeDependencies

Το didChangeDependencies καλείται μετά το initState και σε κάθε αλλαγή εξαρτήσεων InheritedWidget. Εδώ, και όχι στο initState, πρέπει να καλείτε MediaQuery.of(context) ή Theme.of(context), καθώς σε αυτό το σημείο το δέντρο έχει ήδη τοποθετηθεί. Αυτή η μέθοδος καλείται επίσης εάν το widget μεταφερθεί σε άλλο πλαίσιο όπου το InheritedWidget παρέχει διαφορετικές τιμές.

build — δημιουργία UI

Το build είναι η κύρια μέθοδος του State που επιστρέφει το δέντρο widget. Καλείται μετά το initState, μετά το didChangeDependencies και μετά από κάθε setState. Η μέθοδος build δεν πρέπει να έχει παρενέργειες — περιγράφει μόνο τη διεπαφή βάσει των τρεχουσών τιμών των πεδίων του State.

didUpdateWidget

Το didUpdateWidget καλείται όταν ο γονέας ανακατασκευάζει το StatefulWidget με νέες παραμέτρους. Το State έχει πρόσβαση στο παλιό widget μέσω oldWidget και μπορεί να το συγκρίνει με το νέο. Εάν οι παράμετροι άλλαξαν, μπορείτε να ενημερώσετε την κατάσταση, να φορτώσετε νέα δεδομένα ή να επανεκκινήσετε ένα animation.

dispose — απελευθέρωση πόρων

Το dispose είναι η τελική μέθοδος στην οποία απελευθερώνονται όλοι οι πόροι: ελεγκτές, συνδρομές, χρονόμετρα. Μετά το dispose, το State χαρακτηρίζεται ως νεκρό: το mounted επιστρέφει false, η κλήση setState προκαλεί εξαίρεση. Είναι υποχρεωτική η κλήση super.dispose() στην τελευταία γραμμή της μεθόδου.

ΜέθοδοςΠότε καλείταιΥποχρεωτικό super
initStateΚατά τη δημιουργία StateΝαι, στην πρώτη γραμμή
didChangeDependenciesΜετά το initState και σε αλλαγή InheritedWidgetΝαι
buildΜετά από initState, didChangeDependencies, setStateΌχι
didUpdateWidgetΜε νέο widget από τον γονέαΝαι
setStateΜε κλήση από τον προγραμματιστήΌχι
disposeΚατά την αφαίρεση από το δέντροΝαι, στην τελευταία γραμμή

Πώς λειτουργεί το State;

Ο μηχανισμός λειτουργίας του State βασίζεται σε τρεις βασικές αρχές: συσχέτιση με το Element, αντιδραστικότητα μέσω setState και πρόσβαση στον γονέα μέσω της ιδιότητας widget. Όταν το Flutter χτίζει το δέντρο στοιχείων και συναντήσει StatefulElement, καλεί το createState του συνδεδεμένου widget. Το δημιουργημένο State αποθηκεύεται στο στοιχείο και υπάρχει μέχρι το στοιχείο να αφαιρεθεί.

Κατά την κλήση setState, το State επισημαίνεται ως «βρώμικο» (dirty) και προγραμματίζει ανακατασκευή για το επόμενο καρέ. Σημαντικό: το setState δεν καλεί το build άμεσα — απλώς καταγράφει την ανάγκη ανακατασκευής. Το Flutter συλλέγει όλα τα dirty-στοιχεία του τρέχοντος καρέ και τα ανακατασκευάζει μαζικά, βελτιστοποιώντας την απόδοση. Μετά την κλήση build, το State επιστρέφει σε κατάσταση «καθαρό» (clean).

Η ιδιότητα widget επιτρέπει στο State να διαβάζει παραμέτρους που μεταβιβάστηκαν στον κατασκευαστή του StatefulWidget. Επειδή το StatefulWidget είναι αμετάβλητο (όπως το StatelessWidget), τα πεδία του δεν αλλάζουν — όταν αλλάζουν οι παράμετροι, ο γονέας δημιουργεί νέο widget και το State το λαμβάνει μέσω didUpdateWidget. Αυτό εγγυάται ότι το State λειτουργεί πάντα με τα τρέχοντα δεδομένα του γονέα.

Παραδείγματα κώδικα σε Dart

Βασικό παράδειγμα State με πεδίο που αλλάζει μέσω χρονομέτρου. Παρουσιάζει initState, setState και dispose:

dart
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 δευτερόλεπτα πέρασαν');
  }
}

Παράδειγμα χρήσης της ιδιότητας widget για πρόσβαση σε παραμέτρους του γονέα και αντίδραση στις αλλαγές τους μέσω didUpdateWidget:

dart
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('Γεια σου, $_displayName!');
  }
}

Στο δεύτερο παράδειγμα, το State παρακολουθεί την αλλαγή της παραμέτρου εισόδου name και αναμορφώνει την εμφάνιση μόνο σε πραγματική αλλαγή. Χωρίς τον έλεγχο widget.name != oldWidget.name, η μέθοδος θα καλούνταν σε κάθε ανακατασκευή του γονέα, ακόμα κι αν το όνομα δεν άλλαξε — περιττή εργασία για το framework.

State vs StatefulWidget

Το State και το StatefulWidget είναι δύο διαφορετικές κλάσεις στην αρχιτεκτονική Flutter, που εκτελούν διαφορετικούς ρόλους. Το StatefulWidget είναι ένα ελαφρύ αμετάβλητο περιτύλιγμα που περιγράφει τη διαμόρφωση του widget και δημιουργεί το State. Το State είναι ένα βαρύ αντικείμενο που αποθηκεύει μεταβαλλόμενα δεδομένα, διαχειρίζεται συνδρομές και χτίζει το UI. Αυτός ο διαχωρισμός επιτρέπει στο Flutter να καταστρέφει και να δημιουργεί widget χωρίς απώλεια κατάστασης.

Όλα τα πεδία του StatefulWidget πρέπει να είναι final και να ορίζονται στον κατασκευαστή — δεν αλλάζουν μετά τη δημιουργία. Το State, αντίθετα, μπορεί να αλλάζει τα πεδία του ανά πάσα στιγμή, αλλά όλες οι αλλαγές πρέπει να προηγούνται από κλήση setState, ώστε το Flutter να ενημερωθεί για την ανάγκη ανακατασκευής. Αυτή είναι η βασική διαφορά: StatefulWidget — «τι να δείξω», State — «πώς να το δείξω και ποια δεδομένα να χρησιμοποιήσω».

Σύμφωνα με την ανάλυση πηγαίου κώδικα Flutter (Flutter SDK, 2026), το StatefulWidget περιέχει μόνο ένα υποχρεωτικό πεδίο — createState, ενώ το State έχει πρόσβαση στο BuildContext, μπορεί να εγγραφεί σε ροές, να διαχειρίζεται animations και ελεγκτές. Συνιστάται να διατηρείτε το StatefulWidget όσο το δυνατόν πιο απλό, μεταφέροντας όλη τη λογική στο State.

Γιατί το StatefulWidget δεν μπορεί να είναι State;

Ο διαχωρισμός Widget και State είναι μια αρχιτεκτονική απόφαση που διασφαλίζει την αμεταβλητότητα της διαμόρφωσης. Εάν το StatefulWidget αποθήκευε το ίδιο την κατάσταση, σε κάθε ανακατασκευή του γονέα η κατάσταση θα χανόταν. Μεταφέροντας την κατάσταση σε ξεχωριστό αντικείμενο, το Flutter εγγυάται ότι τα δεδομένα επιβιώνουν από ανακατασκευές, ενώ τα widget παραμένουν ελαφριά και συγκρίσιμα.

Διαχείριση κατάστασης μεταξύ widget

Το αντικείμενο State είναι απομονωμένο — δεν έχει άμεση πρόσβαση στο State άλλων widget. Για ανταλλαγή δεδομένων μεταξύ widget χρησιμοποιούνται InheritedWidget ή εξωτερικά εργαλεία διαχείρισης κατάστασης: Provider, Riverpod, Bloc, Redux. Κάθε προσέγγιση λύνει το πρόβλημα με διαφορετικό τρόπο: το InheritedWidget λειτουργεί μέσω του δέντρου widget, το Provider μέσω DI-container, το Bloc μέσω ροών συμβάντων.

Η επιλογή εργαλείου εξαρτάται από την κλίμακα του έργου. Για μια μικρή εφαρμογή, αρκούν τα InheritedWidget και το τοπικό State. Για μεσαίο και μεγάλο έργο, συνιστώνται Riverpod ή Bloc — παρέχουν ελεγξιμότητα, προβλεψιμότητα και διαχωρισμό λογικής από UI. Το State χρησιμοποιείται τότε μόνο για τοπικά δεδομένα του widget (focus, scroll, animation).

Σύμφωνα με το Flutter Community Survey 2025 (Flutter Foundation, Δεκέμβριος 2025), το Riverpod είναι η πιο δημοφιλής λύση διαχείρισης κατάστασης σε νέα έργα (38%), ακολουθούμενο από Bloc (31%) και Provider (22%). Και τα τρία εργαλεία είναι συμβατά με το State και δεν απαιτούν εγκατάλειψη του τυπικού κύκλου ζωής.

Τοπική vs καθολική κατάσταση

  • Τοπική κατάσταση — στο State συγκεκριμένου widget (θέση scroll, κατάσταση focus)
  • Καθολική κατάσταση — σε εξωτερική αποθήκη (δεδομένα χρήστη, ρυθμίσεις, cache)
  • Κανόνας: εάν τα δεδομένα χρησιμοποιούνται μόνο από ένα widget — αποθηκεύστε στο State
  • Εάν τα δεδομένα χρησιμοποιούνται από 2+ widget — μεταφέρετε σε Riverpod/Bloc/Provider

Συνήθη λάθη

Πρώτο λάθος — να ξεχάσετε να ελέγξετε το mounted πριν από setState σε ασύγχρονο callback. Όταν το widget έχει αφαιρεθεί από το δέντρο (π.χ. ο χρήστης έφυγε από την οθόνη), αλλά η ασύγχρονη λειτουργία (HTTP-αίτημα) εκτελείται ακόμα, μετά την ολοκλήρωσή της το State είναι ήδη νεκρό. Η κλήση setState σε νεκρό State προκαλεί εξαίρεση. Ο έλεγχος if (mounted) setState(...) λύνει το πρόβλημα.

Δεύτερο λάθος — αρχικοποίηση εξαρτήσεων InheritedWidget στο initState αντί στο didChangeDependencies. Στο initState το πλαίσιο δεν έχει ακόμα τοποθετηθεί, επομένως MediaQuery.of(context) θα προκαλέσει εξαίρεση. Όλες οι εξαρτήσεις από InheritedWidget πρέπει να ρυθμίζονται στο didChangeDependencies ή στο build.

Τρίτο λάθος — μεταβολή πεδίων χωρίς κλήση setState. Εάν ο προγραμματιστής αλλάζει πεδίο του State χωρίς setState, το Flutter δεν θα ενημερωθεί για την αλλαγή και το UI δεν θα ενημερωθεί. Για παράδειγμα: _list.add(item) χωρίς επόμενο setState((){}) θα αλλάξει τη λίστα, αλλά η οθόνη θα παραμείνει ίδια.

Έλεγχος mounted πριν από setState

Μοτίβο ασφαλείας για ασύγχρονες λειτουργίες σε State:

dart
Future<void> _fetchData() async {
  final data = await ApiService.fetch();
  if (mounted) {
    setState(() => _data = data);
  }
}

Ο έλεγχος mounted διασφαλίζει ότι το setState καλείται μόνο για ζωντανό State, αποτρέποντας την εξαίρεση «setState called after dispose».

Συχνές ερωτήσεις

Πώς διαφέρει το State από το StatefulWidget;

StatefulWidget — αμετάβλητη διαμόρφωση widget, ενώ State — μεταβαλλόμενο αντικείμενο που αποθηκεύει δεδομένα και διαχειρίζεται τον κύκλο ζωής. Το Widget μπορεί να αναδημιουργηθεί, το State — όχι. Το StatefulWidget δημιουργεί το State μέσω createState.

Πόσα αντικείμενα State δημιουργούνται για ένα StatefulWidget;

Ακριβώς ένα. Η μέθοδος createState καλείται μία φορά κατά την πρώτη ενσωμάτωση του StatefulWidget στο δέντρο. Ακόμα κι αν ο γονέας ανακατασκευάζεται πολλές φορές, το αντικείμενο State παραμένει το ίδιο, εφόσον δεν αλλάξει ο τύπος ή το Key του widget.

Τι είναι το mounted στο State;

mounted — boolean σημαία που δείχνει αν το State βρίσκεται στο δέντρο widget. Μετά την κλήση dispose, το mounted γίνεται false. Χρησιμοποιείται για έλεγχο πριν από setState σε ασύγχρονα callbacks, ώστε να αποφευχθεί εξαίρεση.

Μπορώ να χρησιμοποιήσω το State χωρίς StatefulWidget;

Όχι. Το State είναι πάντα συνδεδεμένο με συγκεκριμένο StatefulWidget μέσω generic: State<T extends StatefulWidget>. Δεν είναι αρχιτεκτονικά δυνατό να δημιουργηθεί State απευθείας, χωρίς συσχέτιση με widget.

Τι συμβαίνει αν καλέσω setState στο dispose;

Θα προκληθεί εξαίρεση «setState called after dispose». Μετά την κλήση dispose, το State θεωρείται νεκρό και οποιαδήποτε προσπάθεια ανακατασκευής UI μέσω setState απαγορεύεται. Λύση — ελέγχετε mounted πριν από κάθε setState.

Σύνοψη

  • State — αντικείμενο διαχείρισης δεδομένων του StatefulWidget, που αποθηκεύει μεταβαλλόμενα πεδία και προκαλεί ανακατασκευή UI μέσω setState
  • Κύκλος ζωής περιλαμβάνει τις υποχρεωτικές μεθόδους initState, didChangeDependencies, build, didUpdateWidget και dispose, η καθεμία με τον σκοπό της
  • mounted — κρίσιμη σημαία ασφαλείας που αποτρέπει την κλήση setState μετά την αφαίρεση του widget από το δέντρο
  • widget — ιδιότητα State για πρόσβαση σε παραμέτρους του συνδεδεμένου StatefulWidget, που ενημερώνεται μέσω didUpdateWidget
  • Απομόνωση — το State δεν έχει πρόσβαση σε άλλα State· η επικοινωνία μεταξύ widget γίνεται μέσω InheritedWidget ή εξωτερικών εργαλείων
  • setState — δεν καλεί το build άμεσα, αλλά επισημαίνει το State ως βρώμικο για ανακατασκευή στο επόμενο καρέ
  • Κανόνας — χρησιμοποιείτε State για τοπικά δεδομένα widget· μεταφέρετε την καθολική κατάσταση σε εξωτερικά επίπεδα (Riverpod, Bloc)

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης