Sobes.tech
Junior

Ποια είναι τα hooks στο React;

sobes.tech AI

Απάντηση από AI

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

Ακολουθούν τα βασικά ενσωματωμένα hooks:

  • useState: Επιτρέπει την προσθήκη εσωτερικής κατάστασης σε μια λειτουργική συνιστώσα. Επιστρέφει ένα ζεύγος: την τρέχουσα κατάσταση και μια συνάρτηση για την ενημέρωσή της.

    // Παράδειγμα useState
    import React, { useState } from 'react';
    
    function Counter() {
      const [count, setCount] = useState(0); // Αρχικοποίηση κατάστασης με 0
    
      return (
        <div>
          <p>Έχετε πατήσει {count} φορές</p>
          <button onClick={() => setCount(count + 1)}>
            Πάτησέ με
          </button>
        </div>
      );
    }
    
  • useEffect: Επιτρέπει την εκτέλεση παρενεργειών σε λειτουργικές συνιστώσες. Παρόμοιο με τις μεθόδους κύκλου ζωής των κλασικών συνιστωσών (componentDidMount, componentDidUpdate, componentWillUnmount).

    // Παράδειγμα useEffect
    import React, { useState, useEffect } from 'react';
    
    function Example() {
      const [count, setCount] = useState(0);
    
      // Εκτελείται μετά από κάθε απόδοση
      useEffect(() => {
        document.title = `Έχετε πατήσει ${count} φορές`;
      });
    
      // Εκτελείται μόνο κατά την πρώτη απόδοση (κενό πίνακας εξαρτήσεων)
      useEffect(() => {
        console.log('Η συνιστώσα έχει προσαρτηθεί');
        return () => {
          console.log('Η συνιστώσα έχει αποσυνδεθεί'); // Συνάρτηση καθαρισμού
        };
      }, []);
    
      // Εκτελείται όταν αλλάξει το count
      useEffect(() => {
        console.log('Το count άλλαξε:', count);
      }, [count]);
    
      return (
        <div>
          <p>Έχετε πατήσει {count} φορές</p>
          <button onClick={() => setCount(count + 1)}>
            Πάτησέ με
          </button>
        </div>
      );
    }
    
  • useContext: Επιτρέπει την εγγραφή σε αλλαγές του React context. Δέχεται ένα αντικείμενο context που δημιουργείται με το React.createContext().

    // Παράδειγμα useContext
    import React, { useContext } from 'react';
    
    const ThemeContext = React.createContext('light'); // Δημιουργία context
    
    function ThemedButton() {
      const theme = useContext(ThemeContext); // Χρήση context
    
      return (
        <button className={theme}>
          Κουμπί με θέμα {theme}
        </button>
      );
    }
    
    function App() {
      return (
        <ThemedButton />
      );
    }
    
  • useReducer: Μια εναλλακτική του useState για διαχείριση πιο πολύπλοκων καταστάσεων, που περιλαμβάνουν πολλαπλές υπο-τιμές ή όταν η επόμενη κατάσταση εξαρτάται από την προηγούμενη. Παρόμοιο με τους reducer στο Redux.

    // Παράδειγμα useReducer
    import React, { useReducer } from 'react';
    
    const initialState = { count: 0 };
    
    function reducer(state, action) {
      switch (action.type) {
        case 'increment':
          return { count: state.count + 1 };
        case 'decrement':
          return { count: state.count - 1 };
        default:
          throw new Error();
      }
    }
    
    function Counter() {
      const [state, dispatch] = useReducer(reducer, initialState);
    
      return (
        <>
          Count: {state.count}
          <button onClick={() => dispatch({ type: 'increment' })}>+</button>
          <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
        </>
      );
    }
    
  • useCallback: Μνημονεύει μια συνάρτηση callback. Επιστρέφει μια μνημονευμένη έκδοση της callback, η οποία αλλάζει μόνο αν αλλάξει μια από τις εξαρτήσεις. Χρησιμοποιείται για την αποτροπή περιττών επανακατασκευών παιδικών συστατικών κατά τη μεταβίβαση callbacks.

    // Παράδειγμα useCallback
    import React, { useState, useCallback } from 'react';
    
    function Parent({ addTodo }) {
      const [count, setCount] = useState(0);
    
      const handleAddTodo = useCallback(() => {
        addTodo();
      }, [addTodo]); // Εξάρτηση από addTodo
    
      return (
        <>
          <button onClick={() => setCount(count + 1)}>
            Αύξηση μετρητή
          </button>
          <Child onAddItem={handleAddTodo} />
        </>
      );
    }
    
    function Child({ onAddItem }) {
      console.log('Το παιδικό συστατικό ανακατασκευάζεται'); // Θα ανακατασκευάζεται μόνο αν αλλάξει το onAddItem
      return <button onClick={onAddItem}>Πρόσθεσε στοιχείο</button>;
    }
    
  • useMemo: Μνημονεύει μια υπολογιζόμενη τιμή. Επιστρέφει μια μνημονευμένη τιμή, η οποία επαναυπολογίζεται μόνο αν αλλάξει μια από τις εξαρτήσεις. Χρησιμοποιείται για βελτίωση της απόδοσης σε ακριβές υπολογισμούς.

    // Παράδειγμα useMemo
    import React, { useMemo, useState } from 'react';
    
    function expensiveCalculation(num) {
      console.log('Εκτελείται ακριβής υπολογισμός...');
      for (let i = 0; i < 1000000; i++) {
        num += 1;
      }
      return num;
    }
    
    function Example() {
      const [count, setCount] = useState(0);
      const [todos, setTodos] = useState([]);
    
      const calculation = useMemo(() => expensiveCalculation(count), [count]); // Εξάρτηση από count
    
      const addTodo = () => {
        setTodos(t => [...t, "Νέο Todo"]);
      };
    
      return (
        <div>
          <div>
            <h2>Οι Todo μου</h2>
            {todos.map((todo, index) => (
              <p key={index}>{todo}</p>
            ))}
            <button onClick={addTodo}>Πρόσθεσε Todo</button>
          </div>
          <hr />
          <div>
            Μετρητής: {count}
            <button onClick={() => setCount(c => c + 1)}>+</button>
            <h2>Ακριβής υπολογισμός</h2>
            {calculation}
          </div>
        </div>
      );
    }
    
  • useRef: Επιτρέπει τη δημιουργία μιας μεταβλητής ref, η οποία διατηρείται καθ' όλη τη διάρκεια ζωής του συστατικού. Συχνά χρησιμοποιείται για πρόσβαση σε στοιχεία DOM ή αποθήκευση οποιασδήποτε μεταβλητής που δεν προκαλεί επανακατασκευή.

    // Παράδειγμα useRef
    import React, { useRef } from 'react';
    
    function TextInputWithFocusButton() {
      const inputEl = useRef(null); // Δημιουργία ref
    
      const onButtonClick = () => {
        // current δείχνει το τοποθετημένο στοιχείο DOM
        inputEl.current.focus();
      };
    
      return (
        <>
          <input ref={inputEl} type="text" /> // Σύνδεση ref
          <button onClick={onButtonClick}>Εστίαση στο πεδίο εισαγωγής</button>
        </>
      );
    }
    
  • useImperativeHandle: Ρυθμίζει τον περιγραφέα της στιγμιαίας κατάστασης που παρέχεται στον γονέα κατά τη χρήση του ref. Επιτρέπει στο παιδικό συστατικό να αποκαλύψει ορισμένες μεθόδους στον γονέα. Χρησιμοποιείται μαζί με το forwardRef.

    // Παράδειγμα useImperativeHandle
    import React, { useRef, useImperativeHandle, forwardRef } from 'react';
    
    const MyInput = forwardRef((props, ref) => {
      const inputRef = useRef();
    
      useImperativeHandle(ref, () => ({
        focusInput: () => {
          inputRef.current.focus();
        }
      }));
    
      return <input ref={inputRef} {...props} />;
    });
    
    function ParentComponent() {
      const inputRef = useRef();
    
      const handleFocus = () => {
        inputRef.current.focusInput(); // Metoda από το παιδικό συστατικό
      };
    
      return (
        <div>
          <MyInput ref={inputRef} />
          <button onClick={handleFocus}>Εστίαση μέσω Parent</button>
        </div>
      );
    }
    
  • useLayoutEffect: Παρόμοιο με το useEffect, αλλά εκτελείται συγχρονικά μετά από όλες τις μετατροπές DOM. Χρησιμοποιείται για ανάγνωση δεδομένων από το DOM ή εκτέλεση μετατροπών που πρέπει να γίνουν πριν από την ανανέωση της οθόνης από το πρόγραμμα περιήγησης. Μπορεί να μπλοκάρει το rendering.

    // Παράδειγμα useLayoutEffect
    import React, { useLayoutEffect, useRef } from 'react';
    
    function Tooltip({ children, text }) {
      const ref = useRef(null);
    
      useLayoutEffect(() => {
        if (ref.current) {
          // Υπολογισμοί με βάση το DOM πριν από την ανανέωση
          const { top, height } = ref.current.getBoundingClientRect();
          console.log(`Το στοιχείο βρίσκεται στο ${top} με ύψος ${height}`);
        }
      }, [children]);
    
      return (
        <span ref={ref} title={text}>
          {children}
        </span>
      );
    }
    
  • useDebugValue: Εμφανίζει μια προσαρμοσμένη ετικέτα για τα hooks στα React DevTools. Χρησιμοποιείται σε προσαρμοσμένα hooks για αποσφαλμάτωση.

    // Παράδειγμα useDebugValue
    import React, { useState, useDebugValue } from 'react';
    
    function useFriendStatus(friendID) {
      const [isOnline, setIsOnline] = useState(null);
    
      // Εμφανίζει "Κατάσταση φίλου: Offline" ή "Κατάσταση φίλου: Online" στα DevTools
      useDebugValue(isOnline === true ? 'Online' : 'Offline');
    
      // ... λογική για λήψη κατάστασης φίλου
    
      return isOnline;
    }
    
    function FriendListItem({ friend }) {
      const isOnline = useFriendStatus(friend.id);
    
      return (
        <li style={{ color: isOnline ? 'πράσινο' : 'μαύρο' }}>
          {friend.name} - {isOnline ? 'Online' : 'Offline'}
        </li>
      );
    }
    

Εκτός από τα ενσωματωμένα hooks, υπάρχουν και προσαρμοσμένα hooks (Custom Hooks). Αυτά είναι συναρτήσεις JavaScript που ξεκινούν με "use". Επιτρέπουν την επανάχρηση της λογικής κατάστασης μεταξύ των συστατικών. Ένα προσαρμοσμένο hook μπορεί να καλεί άλλα hooks.

// Παράδειγμα προσαρμοσμένου hook
import { useState, useEffect } from 'react';

function useWindowSize() {
  const [size, setSize] = useState([window.innerWidth, window.innerHeight]);

  useEffect(() => {
    const handleResize = () => {
      setSize([window.innerWidth, window.innerHeight]);
    };
    window.addEventListener('resize', handleResize);
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []);

  return size;
}

function MyComponent() {
  const [width, height] = useWindowSize(); // Χρήση προσαρμοσμένου hook

  return (
    <p>Μέγεθος παραθύρου: {width}x{height}</p>
  );
}

Είναι σημαντικό να ακολουθούνται οι κανόνες των hooks:

  1. Καλείτε τα hooks μόνο στην κορυφή του συστατικού React ή του προσαρμοσμένου hook. Μην τα καλείτε μέσα σε βρόχους, συνθήκες ή εσωτερικές συναρτήσεις.
  2. Καλείτε τα hooks μόνο από λειτουργικά συστατικά React ή προσαρμοσμένα hooks. Μην τα καλείτε από κανονικές JavaScript συναρτήσεις ή μεθόδους κλασικών συστατικών.