Sužinokite, kaip naudoti „React“ individualizuotus „hook'us“, norint iškelti ir pakartotinai panaudoti komponentų logiką, taip pagerinant kodo palaikymą ir testavimą.
React individualizuoti „hook'ai“: komponentų logikos iškėlimas pakartotiniam naudojimui
React „hook'ai“ sukėlė revoliuciją React komponentų rašyme, pasiūlydami elegantiškesnį ir efektyvesnį būdą valdyti būseną (state) ir šalutinius poveikius (side effects). Tarp įvairių galimų „hook'ų“, individualizuoti „hook'ai“ išsiskiria kaip galingas įrankis komponentų logikai iškelti ir pakartotinai naudoti. Šiame straipsnyje pateikiamas išsamus vadovas, kaip suprasti ir įdiegti React individualizuotus „hook'us“, suteikiant galimybę kurti lengviau prižiūrimas, testuojamas ir plečiamas aplikacijas.
Kas yra React individualizuoti „hook'ai“?
Iš esmės, individualizuotas „hook'as“ yra JavaScript funkcija, kurios pavadinimas prasideda žodžiu „use“ ir kuri gali kviesti kitus „hook'us“. Tai leidžia iškelti komponentų logiką į pakartotinai naudojamas funkcijas, taip pašalinant kodo dubliavimą ir skatinant švaresnę komponentų struktūrą. Skirtingai nuo įprastų React komponentų, individualizuoti „hook'ai“ neatvaizduoja jokios vartotojo sąsajos; jie tiesiog inkapsuliuoja logiką.
Galvokite apie juos kaip apie pakartotinai naudojamas funkcijas, kurios gali pasiekti React būseną ir gyvavimo ciklo ypatybes. Tai puikus būdas dalytis būseną turinčia logika tarp skirtingų komponentų, nesinaudojant aukštesnės eilės komponentais (higher-order components) ar atvaizdavimo savybėmis (render props), kurie dažnai gali lemti sunkiai skaitomą ir prižiūrimą kodą.
Kodėl naudoti individualizuotus „hook'us“?
Individualizuotų „hook'ų“ naudojimo privalumai yra gausūs:
- Pakartotinis naudojimas: Parašykite logiką vieną kartą ir naudokite ją keliuose komponentuose. Tai ženkliai sumažina kodo dubliavimą ir padaro jūsų aplikaciją lengviau prižiūrimą.
- Geresnė kodo organizacija: Sudėtingos logikos iškėlimas į individualizuotus „hook'us“ išvalo jūsų komponentus, todėl juos lengviau skaityti ir suprasti. Komponentai tampa labiau orientuoti į savo pagrindines atvaizdavimo pareigas.
- Patobulintas testavimas: Individualizuoti „hook'ai“ yra lengvai testuojami atskirai. Galite testuoti „hook'o“ logiką neatvaizduodami komponento, o tai lemia patikimesnius testus.
- Lengvesnė priežiūra: Kai logika keičiasi, ją reikia atnaujinti tik vienoje vietoje – individualizuotame „hook'e“ – o ne kiekviename komponente, kuriame ji naudojama.
- Mažiau šabloninio kodo: Individualizuoti „hook'ai“ gali inkapsuliuoti įprastus šablonus ir pasikartojančias užduotis, sumažindami šabloninio kodo (boilerplate) kiekį, kurį reikia rašyti komponentuose.
Pirmojo individualizuoto „hook'o“ sukūrimas
Iliustruokime individualizuoto „hook'o“ sukūrimą ir naudojimą praktiniu pavyzdžiu: duomenų gavimas iš API.
Pavyzdys: useFetch
– duomenų gavimo „hook'as“
Įsivaizduokite, kad jums dažnai reikia gauti duomenis iš skirtingų API savo React aplikacijoje. Užuot kartojus duomenų gavimo logiką kiekviename komponente, galite sukurti 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 klaida! Būsena: ${response.status}`);
}
const json = await response.json();
setData(json);
setError(null); // Išvalyti ankstesnes klaidas
} catch (error) {
if (error.name === 'AbortError') {
console.log('Užklausa nutraukta');
} else {
setError(error);
}
setData(null); // Išvalyti ankstesnius duomenis
} finally {
setLoading(false);
}
};
fetchData();
return () => {
abortController.abort(); // Išvalymo funkcija, skirta nutraukti užklausą atjungiant komponentą arba pasikeitus URL
};
}, [url]); // Iš naujo paleisti efektą, kai pasikeičia URL
return { data, loading, error };
}
export default useFetch;
Paaiškinimas:
- Būsenos kintamieji: „Hook'as“ naudoja
useState
duomenims, krovimo būsenai ir klaidos būsenai valdyti. - useEffect:
useEffect
„hook'as“ atlieka duomenų gavimą, kai pasikeičiaurl
savybė. - Klaidų apdorojimas: „Hook'as“ apima klaidų apdorojimą, kad pagautų galimas klaidas užklausos metu. Būsenos kodas yra tikrinamas siekiant užtikrinti, kad atsakymas yra sėkmingas.
- Krovimo būsena:
loading
būsena naudojama nurodyti, ar duomenys vis dar gaunami. - AbortController: Naudoja AbortController API, kad atšauktų užklausą, jei komponentas yra atjungiamas (unmount) arba pasikeičia URL. Tai apsaugo nuo atminties nutekėjimo.
- Grąžinama reikšmė: „Hook'as“ grąžina objektą, kuriame yra
data
,loading
irerror
būsenos.
useFetch
„hook'o“ naudojimas komponente
Dabar pažiūrėkime, kaip naudoti šį individualizuotą „hook'ą“ React komponente:
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>Kraunami vartotojai...</p>;
if (error) return <p>Klaida: {error.message}</p>;
if (!users) return <p>Vartotojų nerasta.</p>;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name} ({user.email})</li>
))}
</ul>
);
}
export default UserList;
Paaiškinimas:
- Komponentas importuoja
useFetch
„hook'ą“. - Jis iškviečia „hook'ą“ su API URL.
- Jis destruktūrizuoja grąžintą objektą, kad pasiektų
data
(pervadintą įusers
),loading
irerror
būsenas. - Jis sąlyginai atvaizduoja skirtingą turinį, priklausomai nuo
loading
irerror
būsenų. - Jei duomenys yra prieinami, jis atvaizduoja vartotojų sąrašą.
Pažangūs individualizuotų „hook'ų“ modeliai
Be paprasto duomenų gavimo, individualizuoti „hook'ai“ gali būti naudojami inkapsuliuoti sudėtingesnę logiką. Štai keletas pažangių modelių:
1. Būsenos valdymas su useReducer
Sudėtingesniems būsenos valdymo scenarijams galite derinti individualizuotus „hook'us“ su useReducer
. Tai leidžia valdyti būsenos pasikeitimus labiau nuspėjamu ir organizuotu būdu.
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;
Naudojimas:
import React from 'react';
import useCounter from './useCounter';
function Counter() {
const { count, increment, decrement } = useCounter();
return (
<div>
<p>Skaičius: {count}</p>
<button onClick={increment}>Didinti</button>
<button onClick={decrement}>Mažinti</button>
</div>
);
}
export default Counter;
2. Konteksto integravimas su useContext
Individualizuoti „hook'ai“ taip pat gali būti naudojami supaprastinti prieigą prie React konteksto (Context). Užuot naudoję useContext
tiesiogiai savo komponentuose, galite sukurti individualizuotą „hook'ą“, kuris inkapsuliuoja konteksto prieigos logiką.
import { useContext } from 'react';
import { ThemeContext } from './ThemeContext'; // Darant prielaidą, kad turite ThemeContext
function useTheme() {
return useContext(ThemeContext);
}
export default useTheme;
Naudojimas:
import React from 'react';
import useTheme from './useTheme';
function MyComponent() {
const { theme, toggleTheme } = useTheme();
return (
<div style={{ backgroundColor: theme.background, color: theme.color }}>
<p>Tai mano komponentas.</p>
<button onClick={toggleTheme}>Perjungti temą</button>
</div>
);
}
export default MyComponent;
3. Debouncing ir Throttling
Debouncing ir throttling yra technikos, naudojamos kontroliuoti, kokiu dažniu vykdoma funkcija. Individualizuoti „hook'ai“ gali būti naudojami šiai logikai inkapsuliuoti, todėl lengva taikyti šias technikas įvykių apdorojimo funkcijoms (event handlers).
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;
Naudojimas:
import React, { useState } from 'react';
import useDebounce from './useDebounce';
function SearchInput() {
const [searchValue, setSearchValue] = useState('');
const debouncedSearchValue = useDebounce(searchValue, 500); // Atidėjimas 500ms
useEffect(() => {
// Atlikti paiešką su atidėta paieškos reikšme (debouncedSearchValue)
console.log('Ieškoma:', debouncedSearchValue);
// Pakeiskite console.log savo realia paieškos logika
}, [debouncedSearchValue]);
const handleChange = (event) => {
setSearchValue(event.target.value);
};
return (
<input
type="text"
value={searchValue}
onChange={handleChange}
placeholder="Ieškoti..."
/>
);
}
export default SearchInput;
Gerosios praktikos rašant individualizuotus „hook'us“
Siekiant užtikrinti, kad jūsų individualizuoti „hook'ai“ būtų efektyvūs ir lengvai prižiūrimi, laikykitės šių gerųjų praktikų:
- Pradėkite su „use“: Visada pavadinkite savo individualizuotus „hook'us“ su priešdėliu „use“. Ši taisyklė signalizuoja React, kad funkcija laikosi „hook'ų“ taisyklių ir gali būti naudojama funkciniuose komponentuose.
- Išlaikykite specifiškumą: Kiekvienas individualizuotas „hook'as“ turėtų turėti aiškų ir konkretų tikslą. Venkite kurti pernelyg sudėtingus „hook'us“, kurie atlieka per daug funkcijų.
- Grąžinkite naudingas reikšmes: Grąžinkite objektą, kuriame yra visos reikšmės ir funkcijos, kurių reikia komponentui, naudojančiam „hook'ą“. Tai daro „hook'ą“ lankstesnį ir labiau pakartotinai naudojamą.
- Apdorokite klaidas: Įtraukite klaidų apdorojimą į savo individualizuotus „hook'us“, kad išvengtumėte netikėto elgesio savo komponentuose.
- Apsvarstykite išvalymą (Cleanup): Naudokite išvalymo funkciją
useEffect
, kad išvengtumėte atminties nutekėjimo ir užtikrintumėte tinkamą resursų valdymą. Tai ypač svarbu dirbant su prenumeratomis, laikmačiais ar įvykių klausytojais. - Rašykite testus: Kruopščiai testuokite savo individualizuotus „hook'us“ atskirai, kad užtikrintumėte, jog jie veikia kaip tikėtasi.
- Dokumentuokite savo „hook'us“: Pateikite aiškią dokumentaciją savo individualizuotiems „hook'ams“, paaiškindami jų paskirtį, naudojimą ir galimus apribojimus.
Globalūs aspektai
Kurdami aplikacijas pasaulinei auditorijai, atsižvelkite į šiuos dalykus:
- Tarptautinimas (i18n) ir lokalizavimas (l10n): Jei jūsų individualizuotas „hook'as“ dirba su vartotojui matomu tekstu ar duomenimis, apsvarstykite, kaip jis bus pritaikytas skirtingoms kalboms ir regionams. Tam gali prireikti naudoti bibliotekas, tokias kaip
react-intl
ari18next
. - Datos ir laiko formatavimas: Būkite atidūs skirtingiems datos ir laiko formatams, naudojamiems visame pasaulyje. Naudokite atitinkamas formatavimo funkcijas ar bibliotekas, kad datos ir laikai būtų rodomi teisingai kiekvienam vartotojui.
- Valiutos formatavimas: Panašiai, tinkamai apdorokite valiutos formatavimą skirtingiems regionams.
- Prieinamumas (a11y): Užtikrinkite, kad jūsų individualizuoti „hook'ai“ neturėtų neigiamos įtakos jūsų aplikacijos prieinamumui. Atsižvelkite į vartotojus su negalia ir laikykitės prieinamumo gerųjų praktikų.
- Našumas: Būkite sąmoningi dėl galimų našumo pasekmių, kurias gali sukelti jūsų individualizuoti „hook'ai“, ypač dirbant su sudėtinga logika ar dideliais duomenų rinkiniais. Optimizuokite savo kodą, kad jis gerai veiktų vartotojams skirtingose vietovėse su skirtingu tinklo greičiu.
Pavyzdys: internacionalizuotas datos formatavimas su individualizuotu „hook'u“
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('Klaida formatuojant datą:', error);
setFormattedDate('Neteisinga data');
}
}, [date, locale]);
return formattedDate;
}
export default useFormattedDate;
Naudojimas:
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>JAV data: {enDate}</p>
<p>Prancūzijos data: {frDate}</p>
<p>Vokietijos data: {deDate}</p>
</div>
);
}
export default MyComponent;
Išvada
React individualizuoti „hook'ai“ yra galingas mechanizmas, skirtas iškelti ir pakartotinai naudoti komponentų logiką. Naudodami individualizuotus „hook'us“, galite rašyti švaresnį, lengviau prižiūrimą ir testuojamą kodą. Tobulėjant jūsų įgūdžiams su React, individualizuotų „hook'ų“ įvaldymas ženkliai pagerins jūsų gebėjimą kurti sudėtingas ir plečiamas aplikacijas. Nepamirškite laikytis gerųjų praktikų ir atsižvelgti į globalius veiksnius kurdami individualizuotus „hook'us“, kad užtikrintumėte jų efektyvumą ir prieinamumą įvairiai auditorijai. Išnaudokite individualizuotų „hook'ų“ galią ir pakelkite savo React programavimo įgūdžius į aukštesnį lygį!