Hrvatski

Naučite kako iskoristiti React custom hookove za izdvajanje i ponovnu upotrebu logike komponente, poboljšavajući održivost koda, testiranje i cjelokupnu arhitekturu aplikacije.

React Custom Hookovi: Izdvajanje Logike Komponente za Ponovnu Upotrebu

React hookovi su revolucionirali način na koji pišemo React komponente, nudeći elegantniji i učinkovitiji način upravljanja stanjem i nuspojavama. Među različitim dostupnim hookovima, custom hookovi se ističu kao moćan alat za izdvajanje i ponovnu upotrebu logike komponente. Ovaj članak pruža sveobuhvatan vodič za razumijevanje i implementaciju React custom hookova, osnažujući vas da izgradite održivije, testabilnije i skalabilnije aplikacije.

Što su React Custom Hookovi?

U suštini, custom hook je JavaScript funkcija čije ime počinje s "use" i može pozivati druge hookove. Omogućuje vam izdvajanje logike komponente u funkcije za ponovnu upotrebu, čime se eliminira dupliciranje koda i promiče čišća struktura komponente. Za razliku od običnih React komponenti, custom hookovi ne renderiraju nikakvo korisničko sučelje; oni jednostavno enkapsuliraju logiku.

Zamislite ih kao funkcije za ponovnu upotrebu koje mogu pristupiti React stanju i značajkama životnog ciklusa. Oni su fantastičan način za dijeljenje logike stanja između različitih komponenti bez pribjegavanja komponentama višeg reda ili render props, što često može dovesti do koda koji je teško čitati i održavati.

Zašto Koristiti Custom Hookove?

Prednosti korištenja custom hookova su brojne:

Stvaranje Vašeg Prvog Custom Hooka

Ilustrirajmo stvaranje i upotrebu custom hooka s praktičnim primjerom: dohvaćanje podataka s API-ja.

Primjer: useFetch - Hook za Dohvaćanje Podataka

Zamislite da često trebate dohvaćati podatke s različitih API-ja u svojoj React aplikaciji. Umjesto ponavljanja logike dohvaćanja u svakoj komponenti, možete stvoriti useFetch hook.


import { useState, useEffect } from 'react';

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

  useEffect(() => {
    const abortController = new AbortController();
    const signal = abortController.signal;

    const fetchData = async () => {
      setLoading(true);
      try {
        const response = await fetch(url, { signal: signal });
        if (!response.ok) {
          throw new Error(`HTTP error! Status: ${response.status}`);
        }
        const json = await response.json();
        setData(json);
        setError(null); // Clear any previous errors
      } catch (error) {
        if (error.name === 'AbortError') {
          console.log('Fetch aborted');
        } else {
          setError(error);
        }
        setData(null); // Clear any previous data
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    return () => {
      abortController.abort(); // Cleanup function to abort the fetch on unmount or URL change
    };
  }, [url]); // Re-run effect when the URL changes

  return { data, loading, error };
}

export default useFetch;

Objašnjenje:

Korištenje useFetch Hooka u Komponenti

Sada, pogledajmo kako koristiti ovaj custom hook u React komponenti:


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

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

  if (loading) return <p>Loading users...</p>;
  if (error) return <p>Error: {error.message}</p>;
  if (!users) return <p>No users found.</p>;

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name} ({user.email})</li>
      ))}
    </ul>
  );
}

export default UserList;

Objašnjenje:

Napredni Obrasci Custom Hookova

Osim jednostavnog dohvaćanja podataka, custom hookovi se mogu koristiti za enkapsulaciju složenije logike. Evo nekoliko naprednih obrazaca:

1. Upravljanje Stanjem s useReducer

Za složenije scenarije upravljanja stanjem, možete kombinirati custom hookove s useReducer. To vam omogućuje upravljanje prijelazima stanja na predvidljiviji i organiziraniji način.


import { 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 useCounter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const increment = () => dispatch({ type: 'increment' });
  const decrement = () => dispatch({ type: 'decrement' });

  return { count: state.count, increment, decrement };
}

export default useCounter;

Upotreba:


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

function Counter() {
  const { count, increment, decrement } = useCounter();

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

export default Counter;

2. Integracija Konteksta s useContext

Custom hookovi se također mogu koristiti za pojednostavljenje pristupa React Kontekstu. Umjesto korištenja useContext izravno u vašim komponentama, možete stvoriti custom hook koji enkapsulira logiku pristupa kontekstu.


import { useContext } from 'react';
import { ThemeContext } from './ThemeContext'; // Assuming you have a ThemeContext

function useTheme() {
  return useContext(ThemeContext);
}

export default useTheme;

Upotreba:


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

function MyComponent() {
  const { theme, toggleTheme } = useTheme();

  return (
    <div style={{ backgroundColor: theme.background, color: theme.color }}>
      <p>This is my component.</p>
      <button onClick={toggleTheme}>Toggle Theme</button>
    </div>
  );
}

export default MyComponent;

3. Debouncing i Throttling

Debouncing i throttling su tehnike koje se koriste za kontrolu brzine kojom se funkcija izvršava. Custom hookovi se mogu koristiti za enkapsulaciju ove logike, što olakšava primjenu ovih tehnika na rukovatelje događajima.


import { useState, useEffect, useRef } from 'react';

function useDebounce(value, delay) {
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => {
      clearTimeout(handler);
    };
  }, [value, delay]);

  return debouncedValue;
}

export default useDebounce;

Upotreba:


import React, { useState } from 'react';
import useDebounce from './useDebounce';

function SearchInput() {
  const [searchValue, setSearchValue] = useState('');
  const debouncedSearchValue = useDebounce(searchValue, 500); // Debounce for 500ms

  useEffect(() => {
    // Perform search with debouncedSearchValue
    console.log('Searching for:', debouncedSearchValue);
    // Replace console.log with your actual search logic
  }, [debouncedSearchValue]);

  const handleChange = (event) => {
    setSearchValue(event.target.value);
  };

  return (
    <input
      type="text"
      value={searchValue}
      onChange={handleChange}
      placeholder="Search..."
    />
  );
}

export default SearchInput;

Najbolje Prakse za Pisanje Custom Hookova

Kako biste osigurali da su vaši custom hookovi učinkoviti i održivi, slijedite ove najbolje prakse:

Globalna Razmatranja

Prilikom razvoja aplikacija za globalnu publiku, imajte na umu sljedeće:

Primjer: Internacionalizirano Oblikovanje Datuma s Custom Hookom


import { useState, useEffect } from 'react';
import { DateTimeFormat } from 'intl';

function useFormattedDate(date, locale) {
  const [formattedDate, setFormattedDate] = useState('');

  useEffect(() => {
    try {
      const formatter = new DateTimeFormat(locale, {
        year: 'numeric',
        month: 'long',
        day: 'numeric',
      });
      setFormattedDate(formatter.format(date));
    } catch (error) {
      console.error('Error formatting date:', error);
      setFormattedDate('Invalid Date');
    }
  }, [date, locale]);

  return formattedDate;
}

export default useFormattedDate;

Upotreba:


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

function MyComponent() {
  const today = new Date();
  const enDate = useFormattedDate(today, 'en-US');
  const frDate = useFormattedDate(today, 'fr-FR');
  const deDate = useFormattedDate(today, 'de-DE');

  return (
    <div>
      <p>US Date: {enDate}</p>
      <p>French Date: {frDate}</p>
      <p>German Date: {deDate}</p>
    </div>
  );
}

export default MyComponent;

Zaključak

React custom hookovi su moćan mehanizam za izdvajanje i ponovnu upotrebu logike komponente. Iskorištavanjem custom hookova možete pisati čišći, održiviji i testabilniji kod. Kako postajete vještiji u Reactu, svladavanje custom hookova značajno će poboljšati vašu sposobnost izgradnje složenih i skalabilnih aplikacija. Zapamtite da slijedite najbolje prakse i razmotrite globalne čimbenike prilikom razvoja custom hookova kako biste osigurali da su učinkoviti i pristupačni za raznoliku publiku. Prigrlite snagu custom hookova i podignite svoje vještine razvoja Reacta!