useEffect: τι είναι, το hook παρενεργειών και ο κύκλος ζωής στο React

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

useEffect — είναι ένα hook του React που σας επιτρέπει να εκτελείτε παρενέργειες σε functional components, αντικαθιστώντας τις μεθόδους κύκλου ζωής των class components: componentDidMount, componentDidUpdate και componentWillUnmount. Σύμφωνα με το React Documentation (2025), το useEffect εκτελείται αφού το React επιβεβαιώσει τις αλλαγές στο DOM, εξασφαλίζοντας πρόσβαση στο τρέχον δέντρο DOM. Το hook δέχεται μια συνάρτηση επίδρασης και έναν προαιρετικό πίνακα εξαρτήσεων που ελέγχει τη συχνότητα εκτέλεσης.

Κύρια Σημεία

  • useEffect — hook για την εκτέλεση παρενεργειών μετά την απόδοση του component.
  • Πίνακας εξαρτήσεων — ελέγχει πότε η επίδραση επανεκτελείται· κενός πίνακας = μία φορά.
  • Καθαρισμός — η συνάρτηση cleanup από την επίδραση καλείται κατά την αφαίρεση και πριν από την επανεκτέλεση.
  • Κύκλος ζωής — αντικαθιστά τα componentDidMount, componentDidUpdate και componentWillUnmount.
  • Σειρά εκτέλεσης — οι επιδράσεις εκτελούνται μετά την επιβεβαίωση αλλαγών στο DOM.

Τι είναι το useEffect στο React

useEffect — είναι ένα hook που προστέθηκε στο React 16.8 για την εκτέλεση παρενεργειών σε functional components. Ως παρενέργειες νοούνται λειτουργίες που δεν σχετίζονται άμεσα με την απόδοση του UI: αιτήματα HTTP σε API, εγγραφές σε συμβάντα, εργασία με χρονοδιακόπτες, χειρισμός DOM, καταγραφή και ενσωμάτωση με βιβλιοθήκες τρίτων.

Πριν από την εμφάνιση των hooks, όλες αυτές οι λειτουργίες έπρεπε να τοποθετούνται στις μεθόδους κύκλου ζωής των class components: componentDidMount για αρχικοποίηση, componentDidUpdate για αντίδραση σε αλλαγές props, componentWillUnmount για καθαρισμό. Το useEffect συνδύασε και τα τρία σενάρια σε ένα ενιαίο API, όπου ο πίνακας εξαρτήσεων καθορίζει πότε πρέπει να εκτελεστεί η επίδραση. Αυτό απλοποίησε τη λογική και μείωσε την επανάληψη κώδικα, ειδικά σε σενάρια με εγγραφές.

Σύμφωνα με το React DevTools Usage Survey (2024), το useEffect είναι το δεύτερο πιο δημοφιλές hook μετά το useState, που χρησιμοποιείται στο 89% των εφαρμογών React. Οι περισσότεροι προγραμματιστές το χρησιμοποιούν για φόρτωση δεδομένων, συγχρονισμό με εξωτερικά συστήματα και διαχείριση εγγραφών σε συμβάντα DOM.

jsx
import { useEffect } from 'react';

function UserProfile({ userId }) {
    useEffect(() => {
        fetch(`/api/users/${userId}`)
            .then(res => res.json())
            .then(data => setUser(data));
    }, [userId]);
}

Πώς λειτουργεί το useEffect: κύκλος ζωής της επίδρασης

useEffect εκτελεί τη συνάρτηση επίδρασης που του δίνεται αφού το React ολοκληρώσει την απόδοση και ενημερώσει το DOM. Αυτή είναι η βασική διαφορά από τους υπολογισμούς κατά την απόδοση: η επίδραση δεν μπλοκάρει τη σχεδίαση, κάτι που είναι κρίσιμο για την απόδοση UX. Αν οι επιδράσεις εκτελούνταν σύγχρονα, ο χρήστης θα έβλεπε μια “παγωμένη” διεπαφή κατά τη φόρτωση δεδομένων.

Ο κύκλος ζωής μιας τυπικής επίδρασης αποτελείται από τρεις φάσεις. Κατά την τοποθέτηση του component, το React εκτελεί την επίδραση. Σε κάθε ενημέρωση, εάν τουλάχιστον μία εξάρτηση από τον πίνακα έχει αλλάξει, το React πρώτα εκτελεί τη συνάρτηση καθαρισμού της προηγούμενης επίδρασης και στη συνέχεια τη νέα επίδραση. Κατά την αφαίρεση του component εκτελείται μόνο η συνάρτηση καθαρισμού.

Σύμφωνα με το React Team — useEffect RFC (2024), η εσωτερική υλοποίηση του useEffect χρησιμοποιεί μια ουρά παρενεργειών στο δέντρο fiber. Μετά την επιβεβαίωση των αλλαγών (commit phase), το React διατρέχει αυτήν την ουρά και καλεί τις συναρτήσεις επίδρασης με τη σειρά δήλωσής τους στο component. Κάθε κόμβος fiber αποθηκεύει μια αναφορά στην προηγούμενη επίδραση για σωστό καθαρισμό και επανεκκίνηση.

ΦάσηΕνέργεια ReactΠότε εκτελείται
ΤοποθέτησηΚλήση συνάρτησης επίδρασηςΜετά την πρώτη απόδοση
Ενημέρωσηcleanup → επίδρασηΌταν αλλάζουν εξαρτήσεις
ΑφαίρεσηΜόνο cleanupΚατά την αφαίρεση component

Πίνακας εξαρτήσεων του useEffect

Ο πίνακας εξαρτήσεων — το δεύτερο όρισμα του useEffect — καθορίζει πότε η επίδραση πρέπει να επανεκκινηθεί. Το React συγκρίνει κάθε τιμή του πίνακα με την προηγούμενη απόδοση χρησιμοποιώντας Object.is. Εάν τουλάχιστον μία τιμή έχει αλλάξει, η επίδραση εκτελείται ξανά. Εάν ο πίνακας είναι κενός ([]), η επίδραση εκτελείται μόνο μία φορά μετά την τοποθέτηση.

Η σωστή επιλογή εξαρτήσεων — το πιο δύσκολο μέρος της εργασίας με το useEffect. Ο πίνακας πρέπει να περιλαμβάνει όλες τις μεταβλητές και συναρτήσεις που χρησιμοποιούνται εντός της επίδρασης και μπορεί να αλλάξουν μεταξύ αποδόσεων. Η παράλειψη μιας εξάρτησης οδηγεί σε stale closures — η επίδραση “βλέπει” μια ξεπερασμένη τιμή από την προηγούμενη απόδοση. Η προσθήκη περιττών εξαρτήσεων οδηγεί σε υπερβολικές επανεκτελέσεις και πιθανά σφάλματα.

jsx
// Οι εξαρτήσεις ελέγχουν πότε η επίδραση εκτελείται ξανά
useEffect(() => {
    document.title = `User: ${user.name}`;
}, [user.name]); // εκτέλεση ξανά μόνο όταν αλλάζει το user.name

// eslint-disable-next-line react-hooks/exhaustive-deps
// Εάν παραλείψετε μια εξάρτηση, λαμβάνετε ξεπερασμένα δεδομένα

Το React παρέχει το πρόσθετο eslint-plugin-react-hooks με τον κανόνα exhaustive-deps, ο οποίος ελέγχει αυτόματα την πληρότητα του πίνακα εξαρτήσεων. Σύμφωνα με το Meta Engineering Blog (2024), η ενεργοποίηση αυτού του πρόσθετου μειώνει τον αριθμό σφαλμάτων που σχετίζονται με hooks κατά 72%. Συνιστάται η διόρθωση όλων των προειδοποιήσεων exhaustive-deps, αντί της καταστολής τους με σχόλιο, εκτός από σπάνιες περιπτώσεις με προσαρμοσμένη λογική.

useEffect χωρίς εξαρτήσεις και με κενό πίνακα

Εάν δεν δώσετε καθόλου πίνακα εξαρτήσεων, το useEffect θα εκτελείται μετά από κάθε απόδοση. Αυτό μπορεί να είναι χρήσιμο για συγχρονισμό με το DOM ή καταγραφή, αλλά συνήθως είναι λάθος: η επίδραση εκτελείται πολύ συχνά, οδηγώντας σε απώλεια απόδοσης. Στις περισσότερες περιπτώσεις, πρέπει να δώσετε έναν κενό πίνακα (μία φορά κατά την τοποθέτηση) ή έναν πίνακα με συγκεκριμένα props/state.

Ο κενός πίνακας ([]) σημαίνει ότι η επίδραση δεν εξαρτάται από καμία τιμή και εκτελείται αυστηρά μία φορά. Αυτό είναι ανάλογο του componentDidMount στα class components. Ωστόσο, πρέπει να θυμάστε: εάν εντός της επίδρασης χρησιμοποιούνται props ή κατάσταση, αλλά δεν αναφέρονται στον πίνακα εξαρτήσεων, η επίδραση θα χρησιμοποιεί τις αρχικές τους τιμές και δεν θα βλέπει ποτέ ενημερώσεις. Αυτό ονομάζεται stale capture και είναι συχνά πηγή δυσκολοεντόπιστων σφαλμάτων.

Πίνακας εξαρτήσεωνΣυμπεριφοράΑνάλογο από κλάσεις
Χωρίς όρισμαΜετά από κάθε απόδοσηcomponentDidUpdate
[]Μία φορά κατά την τοποθέτησηcomponentDidMount
[a, b]Όταν αλλάζει το a ή το bΑνάλογο componentWillReceiveProps
return cleanupΔιαχείριση αφαίρεσηςcomponentWillUnmount

Καθαρισμός επιδράσεων στο useEffect

Η συνάρτηση καθαρισμού (cleanup) — είναι μια συνάρτηση που μπορεί να επιστρέψει το useEffect από το callback του. Το React την καλεί κατά την αφαίρεση του component και πριν από την επανεκτέλεση της επίδρασης όταν αλλάζουν οι εξαρτήσεις. Το cleanup είναι απαραίτητο για την ακύρωση εγγραφών, χρονοδιακοπτών, αιτημάτων και οποιωνδήποτε πόρων που πρέπει να απελευθερωθούν.

Ένα τυπικό παράδειγμα — εγγραφή σε WebSocket. Κατά την τοποθέτηση δημιουργείται η σύνδεση, κατά την ενημέρωση εξαρτήσεων — αναδημιουργείται (το cleanup κλείνει την παλιά, η επίδραση ανοίγει νέα), κατά την αφαίρεση — κλείνει. Χωρίς cleanup, κάθε επανατοποθέτηση του component θα δημιουργούσε νέα σύνδεση WebSocket, οδηγώντας σε διαρροή μνήμης και πολλαπλές συνδέσεις.

jsx
useEffect(() => {
    const socket = new WebSocket('wss://api.example.com');
    socket.onmessage = event => setData(event.data);

    // Συνάρτηση καθαρισμού — εκτελείται κατά την αφαίρεση και πριν από την επανεκτέλεση
    return () => {
        socket.close();
    };
}, []);

Σύμφωνα με το React Documentation (2025), το AbortController — η σύγχρονη προσέγγιση για ακύρωση αιτημάτων fetch στο cleanup. Εάν μια επίδραση κάνει ένα αίτημα HTTP και το component αφαιρεθεί πριν από την ολοκλήρωσή του, το αίτημα συνεχίζει να εκτελείται και το setState μετά την αφαίρεση προκαλεί σφάλμα. Δημιουργήστε ένα AbortController εντός της επίδρασης και καλέστε το controller.abort() στο cleanup για να ακυρώσετε το αίτημα.

Συνηθισμένα λάθη με το useEffect

Το πιο συνηθισμένο λάθος — παράλειψη εξαρτήσεων. Για παράδειγμα, η επίδραση χρησιμοποιεί το prop userId, αλλά ο πίνακας εξαρτήσεων είναι κενός. Ως αποτέλεσμα, η επίδραση εκτελείται μία φορά με την αρχική τιμή του userId και δεν αντιδρά ποτέ στις αλλαγές του. Ο προγραμματιστής βλέπει ότι το component λαμβάνει νέο userId, αλλά τα δεδομένα δεν ενημερώνονται. Το eslint-plugin-react-hooks με τον κανόνα exhaustive-deps ανιχνεύει αυτόματα τέτοια σφάλματα.

  • Ατελείωτος βρόχος — ενημέρωση κατάστασης εντός της επίδρασης που προκαλεί επαναπόδοση, η οποία ενεργοποιεί ξανά την επίδραση. Λύση: ελέγξτε τον πίνακα εξαρτήσεων ή χρησιμοποιήστε τη λειτουργική μορφή του setter.
  • Race condition — εάν το userId αλλάζει γρήγορα, το αίτημα για το πρώτο userId μπορεί να ολοκληρωθεί μετά το αίτημα για το δεύτερο και τα δεδομένα θα εμφανίσουν εσφαλμένο αποτέλεσμα. Λύση: χρησιμοποιήστε μια σημαία cancelled ή AbortController.
  • Περιττές επιδράσεις — συνδυασμός άσχετων λογικών σε ένα useEffect. Το React συνιστά τον διαχωρισμό της λογικής σε πολλές επιδράσεις, ακόμη κι αν έχουν τον ίδιο πίνακα εξαρτήσεων.
  • Ξεχασμένο cleanup — η έλλειψη διαγραφής από συμβάντα, καθαρισμού χρονοδιακοπτών ή ακύρωσης αιτημάτων οδηγεί σε διαρροές μνήμης και σφάλματα setState μετά από αφαίρεση.
jsx
// ❌ Race condition — χωρίς ακύρωση
useEffect(() => {
    fetch(`/api/user/${userId}`).then(res => setUser(res));
}, [userId]);

// ✅ Διορθώθηκε με AbortController
useEffect(() => {
    const controller = new AbortController();
    fetch(`/api/user/${userId}`, { signal: controller.signal })
        .then(res => setUser(res));
    return () => controller.abort();
}, [userId]);

Για να λύσετε το πρόβλημα του ατελείωτου βρόχου, αποφύγετε την τοποθέτηση στο useEffect λογικής που ενημερώνει την κατάσταση βάσει προηγούμενης κατάστασης. Χρησιμοποιήστε τη λειτουργική μορφή του setState ή εκτελέστε υπολογισμούς εκτός της επίδρασης. Εάν η επίδραση εγγράφεται σε storage ή συμβάν προγράμματος περιήγησης, βεβαιωθείτε ότι η παρουσία του ακροατή δημιουργείται μία φορά, όχι σε κάθε απόδοση.

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

Μπορεί να χρησιμοποιηθεί το async/await μέσα στο useEffect;

Άμεσα — όχι, επειδή το useEffect αναμένει την επιστροφή μιας σύγχρονης συνάρτησης ή undefined. Εάν το callback δηλωθεί ως async, επιστρέφει Promise το οποίο το React αγνοεί και ο μηχανισμός καθαρισμού σταματά να λειτουργεί. Λύση: καλέστε την async συνάρτηση εντός της επίδρασης: useEffect(() => { async function load() { ... }; load(); }, []).

Πόσα useEffect μπορούν να υπάρχουν σε ένα component;

Δεν υπάρχει περιορισμός. Το React συνιστά τον διαχωρισμό άσχετης λογικής σε ξεχωριστά useEffect, ακόμη κι αν έχουν τον ίδιο πίνακα εξαρτήσεων. Κάθε επίδραση πρέπει να είναι υπεύθυνη για μία σαφώς καθορισμένη παρενέργεια: μία για εγγραφή, άλλη για φόρτωση δεδομένων, τρίτη για συγχρονισμό τίτλου καρτέλας. Αυτό απλοποιεί την κατανόηση και τον εντοπισμό σφαλμάτων.

Γιατί το useEffect εκτελείται δύο φορές στο StrictMode;

Στο React Strict Mode (μόνο λειτουργία ανάπτυξης) όλες οι επιδράσεις τοποθετούνται, αφαιρούνται και τοποθετούνται ξανά. Αυτό είναι χαρακτηριστικό, όχι σφάλμα — το React ελέγχει εάν ο καθαρισμός λειτουργεί σωστά. Εάν μετά την αφαίρεση και επανατοποθέτηση η επίδραση συμπεριφέρεται λανθασμένα (π.χ. διπλασιάζονται οι εγγραφές), ο καθαρισμός σας είναι ελλιπής. Στην παραγωγή, η επίδραση εκτελείται μία φορά.

Πώς να ακυρώσω ένα αίτημα fetch στο useEffect;

Χρησιμοποιήστε AbortController. Δημιουργήστε ένα controller εντός της επίδρασης, δώστε το controller.signal στο fetch και στο cleanup καλέστε το controller.abort(). Εάν το component αφαιρεθεί πριν από την ολοκλήρωση του αιτήματος, το fetch ακυρώνεται και το setState δεν καλείται. Αυτό αποτρέπει race condition και το σφάλμα “Can't perform a React state update on an unmounted component”.

Τι συμβαίνει αν δεν δώσω πίνακα εξαρτήσεων;

Το useEffect θα εκτελείται μετά από κάθε απόδοση χωρίς εξαίρεση. Αυτό σημαίνει ότι οποιοδήποτε setState εντός της επίδρασης θα προκαλέσει νέα απόδοση → νέα επίδραση → ατελείωτο βρόχο. Στην πράξη, μια επίδραση χωρίς πίνακα εξαρτήσεων είναι σχεδόν πάντα λάθος. Εξαιρέσεις — καταγραφή ή συγχρονισμός με εξωτερικό σύστημα όπου κάθε απόδοση απαιτεί συγχρονισμό.

Περίληψη

  • useEffect — hook για εκτέλεση παρενεργειών μετά την επιβεβαίωση DOM, αντικαθιστά τα componentDidMount, componentDidUpdate και componentWillUnmount.
  • Πίνακας εξαρτήσεων — ελέγχει την επανεκτέλεση της επίδρασης· κενός πίνακας = μία φορά, παράλειψη εξαρτήσεων = stale closure.
  • Cleanup — η συνάρτηση καθαρισμού είναι υποχρεωτική για εγγραφές, χρονοδιακόπτες και αιτήματα· χωρίς αυτήν συμβαίνει διαρροή μνήμης.
  • AbortController — ο σωστός τρόπος ακύρωσης αιτημάτων fetch στο useEffect, αποτρέποντας race condition.
  • StrictMode — τοποθετεί την επίδραση δύο φορές σε λειτουργία ανάπτυξης για έλεγχο ορθότητας καθαρισμού.
  • Διαχωρίστε τις επιδράσεις — κάθε useEffect είναι υπεύθυνο για μία εργασία, ακόμη κι αν οι εξαρτήσεις συμπίπτουν.
  • eslint-plugin-react-hooks — ελέγχει αυτόματα την πληρότητα του πίνακα εξαρτήσεων, μειώνοντας τα σφάλματα κατά 72%.

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

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

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

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