Sobes.tech
Junior

Welke hooks zijn er in React?

sobes.tech AI

Antwoord van AI

In React, vanaf versie 16.8, bieden hooks functionele componenten de mogelijkheid om de staat te beheren en levenscyclusmethoden te gebruiken die eerder alleen beschikbaar waren voor class componenten.

Hier zijn de belangrijkste ingebouwde hooks:

  • useState: Maakt het mogelijk om interne staat toe te voegen aan een functioneel component. Geeft een paar terug: de huidige staat en een functie om deze bij te werken.

    // Voorbeeld useState
    import React, { useState } from 'react';
    
    function Counter() {
      const [count, setCount] = useState(0); // Initialiseer staat op 0
    
      return (
        <div>
          <p>Je hebt {count} keer geklikt</p>
          <button onClick={() => setCount(count + 1)}>
            Klik mij
          </button>
        </div>
      );
    }
    
  • useEffect: Maakt het mogelijk om bijwerkingen uit te voeren in functionele componenten. Vergelijkbaar met de levenscyclusmethoden van class componenten (componentDidMount, componentDidUpdate, componentWillUnmount).

    // Voorbeeld useEffect
    import React, { useState, useEffect } from 'react';
    
    function Example() {
      const [count, setCount] = useState(0);
    
      // Voert uit na elke render
      useEffect(() => {
        document.title = `Je hebt ${count} keer geklikt`;
      });
    
      // Voert alleen uit bij de eerste render (lege afhankelijkheden array)
      useEffect(() => {
        console.log('Component gemonteerd');
        return () => {
          console.log('Component gedemonteerd'); // Cleanup functie
        };
      }, []);
    
      // Voert uit bij verandering van count
      useEffect(() => {
        console.log('Count is veranderd:', count);
      }, [count]);
    
      return (
        <div>
          <p>Je hebt {count} keer geklikt</p>
          <button onClick={() => setCount(count + 1)}>
            Klik mij
          </button>
        </div>
      );
    }
    
  • useContext: Maakt het mogelijk om zich te abonneren op React context veranderingen. Neemt een context object aan, gemaakt met React.createContext().

    // Voorbeeld useContext
    import React, { useContext } from 'react';
    
    const ThemeContext = React.createContext('light'); // Creëer context
    
    function ThemedButton() {
      const theme = useContext(ThemeContext); // Gebruik context
    
      return (
        <button className={theme}>
          Knop in thema {theme}
        </button>
      );
    }
    
    function App() {
      return (
        <ThemedButton />
      );
    }
    
  • useReducer: Alternatief voor useState voor het beheren van complexere staat, die meerdere sub-waarden bevat of wanneer de volgende staat afhankelijk is van de vorige. Vergelijkbaar met reducers in Redux.

    // Voorbeeld 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: Memoiseert callback-functie. Geeft een gememoiseerde versie van de callback die alleen verandert bij verandering van een afhankelijkheid. Handig om onnodige her-renderingen van kindcomponenten te voorkomen bij het doorgeven van callbacks.

    // Voorbeeld useCallback
    import React, { useState, useCallback } from 'react';
    
    function Parent({ addTodo }) {
      const [count, setCount] = useState(0);
    
      const handleAddTodo = useCallback(() => {
        addTodo();
      }, [addTodo]); // Afhankelijkheid van addTodo
    
      return (
        <>
          <button onClick={() => setCount(count + 1)}>
            Verhoog teller
          </button>
          <Child onAddItem={handleAddTodo} />
        </>
      );
    }
    
    function Child({ onAddItem }) {
      console.log('Child wordt gerenderd'); // Wordt alleen gerenderd bij verandering in onAddItem
      return <button onClick={onAddItem}>Voeg item toe</button>;
    }
    
  • useMemo: Memoiseert een berekende waarde. Geeft een gememoiseerde waarde die alleen wordt herberekend bij verandering van een afhankelijkheid. Handig voor prestatieverbeteringen bij dure berekeningen.

    // Voorbeeld useMemo
    import React, { useMemo, useState } from 'react';
    
    function expensiveCalculation(num) {
      console.log('Dure berekening wordt uitgevoerd...');
      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]); // Afhankelijk van count
    
      const addTodo = () => {
        setTodos(t => [...t, "Nieuw Todo"]);
      };
    
      return (
        <div>
          <div>
            <h2>Mijn Todo's</h2>
            {todos.map((todo, index) => (
              <p key={index}>{todo}</p>
            ))}
            <button onClick={addTodo}>Todo toevoegen</button>
          </div>
          <hr />
          <div>
            Teller: {count}
            <button onClick={() => setCount(c => c + 1)}>+</button>
            <h2>Dure berekening</h2>
            {calculation}
          </div>
        </div>
      );
    }
    
  • useRef: Maakt een mutabele ref aan die gedurende de hele levenscyclus van het component behouden blijft. Wordt vaak gebruikt om toegang te krijgen tot DOM-elementen of om elke mutabele waarde op te slaan die geen her-rendering veroorzaakt bij verandering.

    // Voorbeeld useRef
    import React, { useRef } from 'react';
    
    function TextInputWithFocusButton() {
      const inputEl = useRef(null); // Ref maken
    
      const onButtonClick = () => {
        // current wijst naar het gemonteerde DOM-element
        inputEl.current.focus();
      };
    
      return (
        <>
          <input ref={inputEl} type="text" /> // Ref koppelen
          <button onClick={onButtonClick}>Focus op invoerveld</button>
        </>
      );
    }
    
  • useImperativeHandle: Configureert het instantie-object dat wordt verstrekt aan de ouder via ref. Hiermee kan het kind bepaalde methoden aan de ouder blootstellen. Wordt gebruikt samen met forwardRef.

    // Voorbeeld 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(); // Methode aus Kindkomponente aufrufen
      };
    
      return (
        <div>
          <MyInput ref={inputRef} />
          <button onClick={handleFocus}>Fokus via Parent</button>
        </div>
      );
    }
    
  • useLayoutEffect: Ist identisch mit useEffect, wird aber synchron nach allen DOM-Änderungen ausgeführt. Nützlich zum Lesen von DOM-Daten oder Ausführen von Mutationen, die vor dem Browser-Rendern erfolgen müssen. Kann das Rendern blockieren.

    // useLayoutEffect Beispiel
    import React, { useLayoutEffect, useRef } from 'react';
    
    function Tooltip({ children, text }) {
      const ref = useRef(null);
    
      useLayoutEffect(() => {
        if (ref.current) {
          // Berechnungen basierend auf DOM vor dem Rendern
          const { top, height } = ref.current.getBoundingClientRect();
          console.log(`Element befindet sich bei ${top} mit Höhe ${height}`);
        }
      }, [children]);
    
      return (
        <span ref={ref} title={text}>
          {children}
        </span>
      );
    }
    
  • useDebugValue: Zeigt eine benutzerdefinierte Markierung für Hooks in React DevTools an. Wird in benutzerdefinierten Hooks für Debugging verwendet.

    // useDebugValue Beispiel
    import React, { useState, useDebugValue } from 'react';
    
    function useFriendStatus(friendID) {
      const [isOnline, setIsOnline] = useState(null);
    
      // Zeigt in DevTools 'Online' oder 'Offline' an
      useDebugValue(isOnline === true ? 'Online' : 'Offline');
    
      // ... Logik zum Abrufen des Freundestatus
    
      return isOnline;
    }
    
    function FriendListItem({ friend }) {
      const isOnline = useFriendStatus(friend.id);
    
      return (
        <li style={{ color: isOnline ? 'green' : 'black' }}>
          {friend.name} - {isOnline ? 'Online' : 'Offline'}
        </li>
      );
    }
    

Neben den eingebauten Hooks gibt es auch benutzerdefinierte Hooks (Custom Hooks). Das sind JavaScript-Funktionen, deren Namen mit "use" beginnen. Sie ermöglichen die Wiederverwendung von Zustandslogik zwischen Komponenten. Ein benutzerdefinierter Hook kann andere Hooks aufrufen.

// Beispiel benutzerdefinierter 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(); // Verwendung des benutzerdefinierten Hooks

  return (
    <p>Fenstergröße: {width}x{height}</p>
  );
}

Es ist wichtig, die Hook-Regeln einzuhalten:

  1. Rufen Sie Hooks nur auf der obersten Ebene eines React-Komponenten oder eines benutzerdefinierten Hooks auf. Rufen Sie sie nicht innerhalb von Schleifen, Bedingungen oder verschachtelten Funktionen auf.
  2. Rufen Sie Hooks nur in React-Funktionskomponenten oder benutzerdefinierten Hooks auf. Rufen Sie sie nicht in normalen JavaScript-Funktionen oder Klassenmethoden auf.