useRef — τι είναι, το hook αναφοράς και η εργασία με DOM στο React

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

useRef — είναι ένα hook του React που δημιουργεί ένα μεταβαλλόμενο αντικείμενο ref με ιδιότητα .current, το οποίο διατηρείται μεταξύ των render του component. Σε αντίθεση με το useState, η αλλαγή του .current δεν προκαλεί επαναφορά render, καθιστώντας το useRef ιδανικό για αποθήκευση αναφορών DOM, χρονοδιακοπτών και οποιωνδήποτε τιμών που πρέπει να επιβιώνουν στα render χωρίς να επανασχεδιάζουν το UI. Σύμφωνα με το React Documentation (2025), το αντικείμενο ref δημιουργείται μία φορά κατά τη διάρκεια ζωής του component και δεν αλλάζει μεταξύ των render, εγγυώμενο τη σταθερότητα της αναφοράς.

Κύρια σημεία

  • useRef — hook για τη δημιουργία ενός μεταβαλλόμενου αντικειμένου ref με πεδίο .current.
  • Χωρίς επαναφορά render — η αλλαγή του .current δεν προκαλεί επανασχεδιασμό του component.
  • Αναφορές DOM — μεταβιβάζεται στο ref prop του στοιχείου για άμεση πρόσβαση στον κόμβο DOM.
  • Αποθήκευση τιμών — κατάλληλο για χρονοδιακόπτες, προηγούμενες τιμές και οποιαδήποτε δεδομένα μεταξύ render.
  • Σταθερή αναφορά — το αντικείμενο ref δεν αλλάζει μεταξύ των render, σε αντίθεση με τα closures.

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

useRef — είναι ένα hook που προστέθηκε στο React 16.8 και επιστρέφει ένα μεταβαλλόμενο αντικείμενο ref με μία μόνο ιδιότητα .current. Η αρχική τιμή εκχωρείται στο .current κατά την τοποθέτηση (mount) του component. Η κύρια διαφορά από μια συνηθισμένη μεταβλητή — το αντικείμενο ref επιβιώνει της επαναφοράς render: κατά την επαναφορά render, το React δεν δημιουργεί ξανά το ref, αλλά επιστρέφει το ίδιο αντικείμενο.

Η εσωτερική υλοποίηση του useRef χρησιμοποιεί τον ίδιο μηχανισμό με τα useState και useEffect — μια συνδεδεμένη λίστα hooks στον κόμβο fiber. Ωστόσο, σε αντίθεση με το useState, το React δεν παρακολουθεί τις αλλαγές του αντικειμένου ref, δεν βάζει σε ουρά ενημερώσεις και δεν προγραμματίζει επαναφορά render. Αυτό καθιστά το useRef ένα εξαιρετικά ελαφρύ hook που δεν επηρεάζει την απόδοση ακόμα και με συχνές αλλαγές.

Σύμφωνα με το React Team — Hooks FAQ (2025), το useRef είναι ουσιαστικά ένα “kουτί” που αποθηκεύει μια τιμή. Συντακτική ζάχαρη: const ref = useRef(initialValue) είναι ισοδύναμο με const ref = { current: initialValue } με τη διαφορά ότι το React εγγυάται ότι το αντικείμενο ref θα είναι το ίδιο σε κάθε render. Χωρίς μαγεία — απλά μια σταθερή αναφορά που διαχειρίζεται το React.

jsx
import { useRef } from 'react';

function Component() {
    const countRef = useRef(0);
    // countRef.current = 0 αρχικά
    // countRef.current = 5 μετά από μεταβολή
    // Δεν συμβαίνει επαναφορά render!
}

Πρόσβαση σε στοιχεία DOM μέσω useRef

Το πιο συνηθισμένο σενάριο χρήσης του useRef — η απόκτηση άμεσης πρόσβασης στο στοιχείο DOM. Το React εκχωρεί στο elementRef.current την αναφορά στον κόμβο DOM μετά την τοποθέτηση (mount) του component. Αυτό είναι απαραίτητο για την εστίαση input, τη μέτρηση διαστάσεων στοιχείου, την ενσωμάτωση με βιβλιοθήκες κινουμένων σχεδίων και βιβλιοθήκες που δεν χρησιμοποιούν render του React.

Το React διαχειρίζεται αυτόματα τις αναφορές ref στο DOM: κατά την τοποθέτηση εκχωρεί τον πραγματικό κόμβο DOM, κατά την αφαίρεση τον μηδενίζει (θέτει null). Αυτό εγγυάται ότι το .current περιέχει πάντα μια ενημερωμένη τιμή και αποτρέπει διαρροές μνήμης μέσω “kρεμαστών” αναφορών σε διαγραμμένα στοιχεία. Δεν απαιτείται χειροκίνητος καθαρισμός.

jsx
function AutoFocusInput() {
    const inputRef = useRef(null);

    useEffect(() => {
        // Εστίαση input μετά την τοποθέτηση του component
        inputRef.current?.focus();
    }, []);

    return <input ref={inputRef} type="text" />;
}

Σύμφωνα με το React — Refs and DOM documentation (2025), μην χρησιμοποιείτε το ref για δηλωτικές λειτουργίες — άνοιγμα/κλείσιμο modals, διαχείριση ορατότητας. Για αυτούς τους σκοπούς υπάρχουν το state και τα props. Τα refs προορίζονται για προστακτικές λειτουργίες που δεν μπορούν να εκφραστούν δηλωτικά: εστίαση, επιλογή κειμένου, ενσωμάτωση με βιβλιοθήκες τρίτων.

Αποθήκευση μεταβαλλόμενων τιμών χωρίς επαναφορά render

Το δεύτερο πιο σημαντικό σενάριο — αποθήκευση αυθαίρετων τιμών που πρέπει να διατηρούνται μεταξύ των render, αλλά η αλλαγή τους δεν πρέπει να προκαλεί επαναφορά render. Τυπικά παραδείγματα: αναγνωριστικά χρονοδιακοπτών (setInterval/setTimeout), σημαίες για ακύρωση αιτημάτων, προηγούμενες τιμές props για σύγκριση και οποιαδήποτε δεδομένα δεν επηρεάζουν την έξοδο του UI.

Αυτό είναι ιδιαίτερα χρήσιμο στο useEffect: το useRef αποθηκεύει το αναγνωριστικό του χρονοδιακόπτη και το cleanup το διαγράφει. Εάν το timerId αποθηκευτεί στο useState, κάθε κλήση setTimerId θα προκαλούσε μια περιττή επαναφορά render που δεν είναι απαραίτητη ούτε για τη λογική ούτε για το UI. Το useRef λύνει αυτό το πρόβλημα χωρίς επιβάρυνση και χωρίς περιττούς επανασχεδιασμούς.

jsx
function Timer() {
    const intervalRef = useRef(null);

    const start = () => {
        intervalRef.current = setInterval(() => {
            console.log('χτύπος');
        }, 1000);
    };

    const stop = () => {
        clearInterval(intervalRef.current);
    };

    useEffect(() => stop, []);

    return <><button onClick={start}>Start</button><button onClick={stop}>Stop</button></>;
}

useRef vs useState: πότε να χρησιμοποιείτε τι

Το κύριο δίλημμα — η επιλογή μεταξύ useRef και useState — λύνεται με μία ερώτηση: “Χρειάζεται επαναφορά render κατά την αλλαγή τιμής;”. Αν ναι — useState. Αν όχι — useRef. Το useState αποθηκεύει κατάσταση που επηρεάζει την έξοδο του component· το useRef αποθηκεύει δεδομένα που χρειάζονται για την εσωτερική λογική, αλλά δεν επηρεάζουν το UI.

Στην πράξη, οι προγραμματιστές συχνά χρησιμοποιούν το useRef για να αποθηκεύουν callbacks, για να αποφεύγουν προβλήματα με closures. Για παράδειγμα, εάν το useEffect εγγράφεται σε ένα συμβάν και μέσα στο callback χρειάζεται το τρέχον state — αποθηκεύστε το callback στο useRef. Σε κάθε render ενημερώστε το ref.current με τη νέα συνάρτηση και το εφέ θα καλεί πάντα το φρέσκο callback χωρίς επανεγγραφή.

ΚριτήριοuseRefuseState
Επαναφορά renderΔεν προκαλεί σε αλλαγήΠροκαλεί σε κάθε setState
ΜεταβολήΆμεση: ref.current = valueΜέσω setter: setState(value)
Χρήση σε JSXΔεν χρησιμοποιείται (χωρίς εφέ)Χρησιμοποιείται στην έξοδο του component
ΠαράδειγμαΧρονοδιακόπτες, αναφορές DOM, προηγούμενες τιμέςΔεδομένα φόρμας, κατάσταση UI, σημαίες

Υπάρχει ένα anti-pattern: η χρήση του useRef για αποθήκευση δεδομένων που χρειάζονται στο JSX, αλλά η αλλαγή τους δεν πρέπει να προκαλεί επαναφορά render. Αυτό οδηγεί σε αποσυγχρονισμό — το UI εμφανίζει παλιά δεδομένα, ενώ το ref.current είναι ήδη νέο. Εάν η τιμή εμφανίζεται στο UI — χρησιμοποιήστε useState. Εάν χρησιμοποιείται μόνο εντός της λογικής — useRef.

Το useRef σε συνδυασμό με το useEffect

Ο συνδυασμός useRef + useEffect — ένα τυπικό μοτίβο για την παρακολούθηση προηγούμενων τιμών props. Αποθηκεύστε την προηγούμενη τιμή στο ref, συγκρίνετε με την τρέχουσα στο useEffect και λάβετε απόφαση βάσει της διαφοράς. Αυτό είναι ιδιαίτερα χρήσιμο σε κινούμενα σχέδια, όταν πρέπει να γνωρίζετε ποια τιμή ήταν πριν από την αλλαγή.

jsx
function PriceDisplay({ price }) {
    const prevPriceRef = useRef(price);

    useEffect(() => {
        const prevPrice = prevPriceRef.current;
        if (price > prevPrice) {
            animateUp();
        } else if (price < prevPrice) {
            animateDown();
        }
        prevPriceRef.current = price;
    }, [price]);

    return <span>${price}</span>;
}

Σύμφωνα με το React Documentation — Hooks FAQ (2025), αυτό το μοτίβο ονομάζεται “previous value pattern”. Λειτουργεί επειδή το useRef διατηρεί την τιμή μεταξύ των render και το useEffect εκτελείται μετά την επιβεβαίωση των αλλαγών. Πρώτα το DOM ενημερώνεται με τη νέα price, στη συνέχεια το useEffect συγκρίνει με την προηγούμενη (που είναι ακόμα στο ref) και ενημερώνει το ref.current στην τρέχουσα τιμή.

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

Το πιο συνηθισμένο λάθος — η ανάγνωση του ref.current στη φάση render για τον υπολογισμό JSX. Δεδομένου ότι η αλλαγή του ref.current δεν προκαλεί επαναφορά render, το component μπορεί να χρησιμοποιεί μια παλιά τιμή. Εάν η τιμή του .current συμμετέχει στην έξοδο UI — χρησιμοποιήστε useState. Εάν χρειάζεται να συγχρονίσετε ref και state, χρησιμοποιήστε useEffect για ενημέρωση του state από το ref.

  • Ref στο JSX — η ανάγνωση του ref.current μέσα στη συνάρτηση render οδηγεί σε αποσυγχρονισμό UI και δεδομένων.
  • Ref ως εξάρτηση useEffect — το ref.current δεν πρέπει να βρίσκεται στον πίνακα εξαρτήσεων· το React δεν παρακολουθεί τις αλλαγές του.
  • Ξεχασμένος έλεγχος null — κατά την αφαίρεση, το ref.current γίνεται null· ελέγξτε πριν την πρόσβαση.
  • Αποθήκευση συναρτήσεων στο ref — ενημερώστε το ref.current σε κάθε render εάν χρησιμοποιείτε το μοτίβο με φρέσκο callback.
jsx
// ❌ Μην διαβάζετε το ref.current κατά τη διάρκεια του render για εμφάνιση
function BadComponent() {
    const valRef = useRef(0);
    return <p>{valRef.current}</p>; // ΔΕΝ θα ενημερωθεί σε μεταβολή
}

// ✅ Χρησιμοποιήστε state για εμφάνιση, ref για λογική
function GoodComponent() {
    const [val, setVal] = useState(0);
    const valRef = useRef(0);
    return <p>{val}</p>;
}

Ένα άλλο συνηθισμένο λάθος — η χρήση του useRef ως ο μοναδικός τρόπος αποθήκευσης κατάστασης στο component, όταν τα δεδομένα επηρεάζουν τελικά το UI. Οι προγραμματιστές επιλέγουν το useRef για να αποφύγουν “περιττές” επαναφορές render, αλλά στο τέλος λαμβάνουν ένα UI που δεν ενημερώνεται. Η σωστή προσέγγιση: χρησιμοποιήστε useState για δεδομένα UI και useRef μόνο για βοηθητικές τιμές που δεν συμμετέχουν στο render.

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

Μπορεί να χρησιμοποιηθεί το useRef για αποθήκευση προηγούμενης κατάστασης;

Ναι, αυτό είναι ένα κοινό μοτίβο — previous state pattern. Δημιουργήστε ένα ref και ενημερώστε το στο useEffect σε κάθε αλλαγή της παρακολουθούμενης τιμής. Τη στιγμή μεταξύ render και εφέ, το ref.current περιέχει την προηγούμενη τιμή που μπορεί να συγκριθεί με την τρέχουσα. Αυτό δεν απαιτεί πρόσθετες επαναφορές render και λειτουργεί με όλους τους τύπους δεδομένων.

Γιατί το ref.current είναι null στο πρώτο render;

Το React εκχωρεί στο ref.current την τιμή του κόμβου DOM μόνο αφού το στοιχείο έχει γίνει render και προστεθεί στο πραγματικό DOM. Κατά το πρώτο render, το component δεν έχει ακόμα τοποθετηθεί (mounted), επομένως το ref.current είναι ίσο με την αρχική τιμή (null). Η πρόσβαση στο DOM μέσω ref.current είναι δυνατή μόνο στο useEffect ή σε χειριστές γεγονότων που καλούνται μετά την τοποθέτηση.

Ποια είναι η διαφορά μεταξύ useRef και createRef;

createRef δημιουργεί ένα νέο αντικείμενο ref σε κάθε render — πρέπει να χρησιμοποιείται μόνο σε class components. useRef δημιουργεί το ref μία φορά και επιστρέφει το ίδιο αντικείμενο σε όλα τα επόμενα render. Σε functional components, χρησιμοποιείτε αποκλειστικά το useRef· το createRef θα οδηγήσει σε απώλεια της τιμής κατά την επαναφορά render, καθώς το αντικείμενο θα δημιουργηθεί ξανά.

Μπορεί το useRef να μεταβιβαστεί μέσω props;

Ναι, το αντικείμενο ref μπορεί να μεταβιβαστεί ως κανονικό prop: <Child inputRef={inputRef} />. Το child component το χρησιμοποιεί μέσω inputRef.current. Ωστόσο, για την απευθείας μεταβίβαση ref στο στοιχείο DOM του child component, χρησιμοποιήστε το forwardRef — ένα HOC που επιτρέπει τη διέλευση του ref μέσω props. Χωρίς forwardRef, το ref δεν θα συνδεθεί αυτόματα με το στοιχείο DOM μέσα στο child component.

Πώς να μετρήσετε τη διάσταση ενός στοιχείου με useRef;

Συνδέστε το ref στο στοιχείο, στη συνέχεια στο useEffect διαβάστε το ref.current.getBoundingClientRect() ή το ref.current.offsetWidth / offsetHeight. Για αντιδραστική παρακολούθηση αλλαγών μεγέθους, χρησιμοποιήστε ResizeObserver μέσα στο useEffect: δημιουργήστε observer, εγγραφείτε σε αλλαγές και ενημερώστε το state με νέες διαστάσεις. Μην ξεχάσετε να απενεργοποιήσετε τον observer στο cleanup.

Περίληψη

  • useRef — hook για τη δημιουργία ενός μεταβαλλόμενου αντικειμένου ref που διατηρείται μεταξύ render χωρίς να προκαλεί επαναφορά render.
  • Πρόσβαση DOM — το ref prop μεταβιβάζεται στο στοιχείο για άμεση πρόσβαση στον κόμβο DOM· διαθέσιμο μετά την τοποθέτηση.
  • Αποθήκευση δεδομένων — χρονοδιακόπτες, callbacks, σημαίες και οποιεσδήποτε τιμές δεν επηρεάζουν το UI αποθηκεύστε στο ref.
  • useRef vs useState — επιλέξτε useState εάν η αλλαγή πρέπει να επανασχεδιάσει το UI· useRef — εάν όχι.
  • Previous value pattern — αποθηκεύστε την προηγούμενη τιμή στο ref, ενημερώστε στο useEffect για σύγκριση.
  • Ref στο JSX — μην διαβάζετε το ref.current στη φάση render· αυτό οδηγεί σε αποσυγχρονισμό UI και δεδομένων.
  • forwardRef — χρησιμοποιήστε για μεταβίβαση ref μέσω props στο child component.

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

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

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

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