Română

Deblocați logica reutilizabilă în aplicațiile React cu hook-uri personalizate. Creați cod mai curat și mentenabil învățând cum să le creați și să le folosiți.

Hook-uri Personalizate: Pattern-uri de Logică Reutilizabilă în React

Hook-urile React au revoluționat modul în care scriem componentele React prin introducerea stării (state) și a caracteristicilor ciclului de viață (lifecycle) în componentele funcționale. Printre numeroasele beneficii pe care le oferă, hook-urile personalizate se remarcă drept un mecanism puternic pentru extragerea și reutilizarea logicii între multiple componente. Acest articol de blog va explora în profunzime lumea hook-urilor personalizate, analizând beneficiile, crearea și utilizarea acestora cu exemple practice.

Ce sunt Hook-urile Personalizate?

În esență, un hook personalizat este o funcție JavaScript care începe cu cuvântul "use" și poate apela alte hook-uri. Acestea vă permit să extrageți logica componentelor în funcții reutilizabile. Aceasta este o modalitate puternică de a partaja logica cu stare (stateful), efectele secundare (side effects) sau alte comportamente complexe între componente, fără a recurge la render props, componente de ordin superior (higher-order components) sau alte pattern-uri complexe.

Caracteristici Cheie ale Hook-urilor Personalizate:

Beneficiile Utilizării Hook-urilor Personalizate

Hook-urile personalizate oferă mai multe avantaje semnificative în dezvoltarea cu React:

Crearea Primului Vostru Hook Personalizat

Să ilustrăm crearea unui hook personalizat cu un exemplu practic: un hook care urmărește dimensiunea ferestrei.

Exemplu: useWindowSize

Acest hook va returna lățimea și înălțimea curentă a ferestrei browserului. De asemenea, va actualiza aceste valori atunci când fereastra este redimensionată.

import { useState, useEffect } from 'react';

function useWindowSize() {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    function handleResize() {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }

    window.addEventListener('resize', handleResize);

    // Elimină event listener-ul la curățare
    return () => window.removeEventListener('resize', handleResize);
  }, []); // Array-ul gol asigură că efectul se execută doar la montare

  return windowSize;
}

export default useWindowSize;

Explicație:

  1. Importul Hook-urilor Necesare: Importăm useState și useEffect din React.
  2. Definirea Hook-ului: Creăm o funcție numită useWindowSize, respectând convenția de denumire.
  3. Inițializarea Stării: Folosim useState pentru a inițializa starea windowSize cu lățimea și înălțimea inițială a ferestrei.
  4. Configurarea Event Listener-ului: Folosim useEffect pentru a adăuga un event listener de redimensionare la fereastră. Când fereastra este redimensionată, funcția handleResize actualizează starea windowSize.
  5. Curățarea (Cleanup): Returnăm o funcție de curățare din useEffect pentru a elimina event listener-ul atunci când componenta este demontată. Acest lucru previne scurgerile de memorie.
  6. Returnarea Valorilor: Hook-ul returnează obiectul windowSize, care conține lățimea și înălțimea curentă a ferestrei.

Utilizarea Hook-ului Personalizat într-o Componentă

Acum că am creat hook-ul nostru personalizat, să vedem cum să îl folosim într-o componentă React.

import React from 'react';
import useWindowSize from './useWindowSize';

function MyComponent() {
  const { width, height } = useWindowSize();

  return (
    

Lățimea ferestrei: {width}px

Înălțimea ferestrei: {height}px

); } export default MyComponent;

Explicație:

  1. Importul Hook-ului: Importăm hook-ul personalizat useWindowSize.
  2. Apelarea Hook-ului: Apelăm hook-ul useWindowSize în cadrul componentei.
  3. Accesarea Valorilor: Destructurăm obiectul returnat pentru a obține valorile width și height.
  4. Redarea Valorilor: Redăm valorile de lățime și înălțime în interfața grafică a componentei.

Orice componentă care utilizează useWindowSize se va actualiza automat atunci când dimensiunea ferestrei se schimbă.

Exemple Mai Complexe

Să explorăm câteva cazuri de utilizare mai avansate pentru hook-urile personalizate.

Exemplu: useLocalStorage

Acest hook vă permite să stocați și să preluați cu ușurință date din local storage.

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  // Stare pentru a stoca valoarea noastră
  // Pasează valoarea inițială la useState astfel încât logica să fie executată o singură dată
  const [storedValue, setStoredValue] = useState(() => {
    try {
      // Preia din local storage după cheie
      const item = window.localStorage.getItem(key);
      // Parsează JSON-ul stocat sau, dacă nu există, returnează initialValue
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // Dacă apare o eroare, returnează tot initialValue
      console.log(error);
      return initialValue;
    }
  });

  // Returnează o versiune împachetată a funcției setter a lui useState care ...
  // ... persistă noua valoare în localStorage.
  const setValue = (value) => {
    try {
      // Permite ca valoarea să fie o funcție, astfel încât să avem același API ca useState
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      // Salvează în local storage
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
      // Salvează starea
      setStoredValue(valueToStore);
    } catch (error) {
      // O implementare mai avansată ar gestiona cazul de eroare
      console.log(error);
    }
  };

  useEffect(() => {
    try {
      const item = window.localStorage.getItem(key);
      setStoredValue(item ? JSON.parse(item) : initialValue);
    } catch (error) {
      console.log(error);
    }
  }, [key, initialValue]);

  return [storedValue, setValue];
}

export default useLocalStorage;

Utilizare:

import React from 'react';
import useLocalStorage from './useLocalStorage';

function MyComponent() {
  const [name, setName] = useLocalStorage('name', 'Oaspete');

  return (
    

Salut, {name}!

setName(e.target.value)} />
); } export default MyComponent;

Exemplu: useFetch

Acest hook încapsulează logica pentru preluarea datelor de la un API.

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error(`Eroare HTTP! status: ${response.status}`);
        }
        const json = await response.json();
        setData(json);
        setLoading(false);
      } catch (error) {
        setError(error);
        setLoading(false);
      }
    }

    fetchData();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;

Utilizare:

import React from 'react';
import useFetch from './useFetch';

function MyComponent() {
  const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');

  if (loading) return 

Se încarcă...

; if (error) return

Eroare: {error.message}

; return (

Titlu: {data.title}

Finalizat: {data.completed ? 'Da' : 'Nu'}

); } export default MyComponent;

Cele Mai Bune Practici pentru Hook-urile Personalizate

Pentru a vă asigura că hook-urile personalizate sunt eficiente și ușor de întreținut, urmați aceste bune practici:

Capcane Comune de Evitat

Pattern-uri Avansate

Compunerea Hook-urilor Personalizate

Hook-urile personalizate pot fi compuse împreună pentru a crea o logică mai complexă. De exemplu, ați putea combina un hook useLocalStorage cu un hook useFetch pentru a persista automat datele preluate în local storage.

Partajarea Logicii între Hook-uri

Dacă mai multe hook-uri personalizate partajează o logică comună, puteți extrage acea logică într-o funcție utilitară separată și o puteți reutiliza în ambele hook-uri.

Utilizarea Context cu Hook-uri Personalizate

Hook-urile personalizate pot fi utilizate în conjuncție cu React Context pentru a accesa și actualiza starea globală. Acest lucru vă permite să creați componente reutilizabile care sunt conștiente de și pot interacționa cu starea globală a aplicației.

Exemple din Lumea Reală

Iată câteva exemple despre cum pot fi utilizate hook-urile personalizate în aplicații reale:

Exemplu: hook-ul useGeolocation pentru aplicații interculturale precum servicii de hărți sau livrare

import { useState, useEffect } from 'react';

function useGeolocation() {
  const [location, setLocation] = useState({
    latitude: null,
    longitude: null,
    error: null,
  });

  useEffect(() => {
    if (!navigator.geolocation) {
      setLocation({
        latitude: null,
        longitude: null,
        error: 'Geolocația nu este suportată de acest browser.',
      });
      return;
    }

    const watchId = navigator.geolocation.watchPosition(
      (position) => {
        setLocation({
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          error: null,
        });
      },
      (error) => {
        setLocation({
          latitude: null,
          longitude: null,
          error: error.message,
        });
      }
    );

    return () => navigator.geolocation.clearWatch(watchId);
  }, []);

  return location;
}

export default useGeolocation;

Concluzie

Hook-urile personalizate sunt un instrument puternic pentru a scrie cod React mai curat, mai reutilizabil și mai ușor de întreținut. Prin încapsularea logicii complexe în hook-uri personalizate, puteți simplifica componentele, reduce duplicarea codului și îmbunătăți structura generală a aplicațiilor voastre. Adoptați hook-urile personalizate și deblocați potențialul lor de a construi aplicații React mai robuste și scalabile.

Începeți prin a identifica zonele din baza de cod existentă unde logica se repetă în mai multe componente. Apoi, refactorizați acea logică în hook-uri personalizate. În timp, veți construi o bibliotecă de hook-uri reutilizabile care vă vor accelera procesul de dezvoltare și vor îmbunătăți calitatea codului.

Amintiți-vă să urmați cele mai bune practici, să evitați capcanele comune și să explorați pattern-uri avansate pentru a profita la maximum de hook-urile personalizate. Cu practică și experiență, veți deveni un maestru al hook-urilor personalizate și un dezvoltator React mai eficient.