Hyödynnä Reactin custom-hookien ja efektien koostamisen teho sovellustesi monimutkaisten sivuvaikutusten hallintaan. Opi orkestroimaan efektejä puhtaamman ja ylläpidettävämmän koodin aikaansaamiseksi.
Reactin custom-hookien efektikompositio: Monimutkaisten efektien orkestroinnin hallinta
Reactin custom-hookit ovat mullistaneet tavan, jolla hallitsemme tilallista logiikkaa ja sivuvaikutuksia sovelluksissamme. Vaikka useEffect
on tehokas työkalu, monimutkaisista komponenteista voi nopeasti tulla hankalia useiden, toisiinsa kietoutuneiden efektien vuoksi. Tässä kohtaa efektien koostaminen astuu kuvaan – tekniikka, joka antaa meille mahdollisuuden pilkkoa monimutkaiset efektit pienemmiksi, uudelleenkäytettäviksi custom-hookeiksi, mikä johtaa puhtaampaan ja ylläpidettävämpään koodiin.
Mitä on efektien koostaminen?
Efektien koostaminen on käytäntö, jossa yhdistetään useita pienempiä efektejä, jotka on tyypillisesti kapseloitu custom-hookeihin, suuremman ja monimutkaisemman efektin luomiseksi. Sen sijaan, että ahtaisimme kaiken logiikan yhteen useEffect
-kutsuun, luomme uudelleenkäytettäviä toiminnallisuusyksiköitä, joita voidaan koostaa yhteen tarpeen mukaan. Tämä lähestymistapa edistää koodin uudelleenkäytettävyyttä, parantaa luettavuutta ja yksinkertaistaa testaamista.
Miksi käyttää efektien koostamista?
On useita painavia syitä omaksua efektien koostaminen React-projekteissasi:
- Parempi koodin uudelleenkäytettävyys: Custom-hookeja voidaan käyttää uudelleen useissa komponenteissa, mikä vähentää koodin monistamista ja parantaa ylläpidettävyyttä.
- Parannettu luettavuus: Monimutkaisten efektien pilkkominen pienemmiksi, kohdennetuiksi yksiköiksi tekee koodista helpommin ymmärrettävää ja pääteltävää.
- Yksinkertaistettu testaaminen: Pienempiä, eristettyjä efektejä on helpompi testata ja debugata.
- Lisääntynyt modulaarisuus: Efektien koostaminen edistää modulaarista arkkitehtuuria, mikä helpottaa toiminnallisuuksien lisäämistä, poistamista tai muokkaamista vaikuttamatta sovelluksen muihin osiin.
- Vähentynyt monimutkaisuus: Suuren määrän sivuvaikutuksia hallinta yhdessä
useEffect
-kutsussa voi johtaa spagettikoodiin. Efektien koostaminen auttaa pilkkomaan monimutkaisuuden hallittaviksi paloiksi.
Perusesimerkki: Datan haun ja paikalliseen tallennustilaan tallentamisen yhdistäminen
Tarkastellaan tilannetta, jossa meidän on haettava käyttäjätietoja API:sta ja tallennettava ne paikalliseen tallennustilaan (local storage). Ilman efektien koostamista saattaisimmee päätyä yhteen useEffect
-kutsuun, joka hoitaa molemmat tehtävät. Näin voimme saavuttaa saman tuloksen efektien koostamisella:
1. useFetchData
-hookin luominen
Tämä hook on vastuussa datan hakemisesta API:sta.
import { useState, useEffect } from 'react';
function useFetchData(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const json = await response.json();
setData(json);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
export default useFetchData;
2. useLocalStorage
-hookin luominen
Tämä hook hoitaa datan tallentamisen paikalliseen tallennustilaan.
import { useState, useEffect } from 'react';
function useLocalStorage(key, initialValue) {
const [storedValue, setStoredValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
useEffect(() => {
try {
window.localStorage.setItem(key, JSON.stringify(storedValue));
} catch (error) {
console.error(error);
}
}, [key, storedValue]);
return [storedValue, setStoredValue];
}
export default useLocalStorage;
3. Hookien koostaminen komponentissa
Nyt voimme koostaa nämä hookit komponentissa hakeaksemme käyttäjätiedot ja tallentaaksemme ne paikalliseen tallennustilaan.
import React from 'react';
import useFetchData from './useFetchData';
import useLocalStorage from './useLocalStorage';
function UserProfile() {
const { data: userData, loading, error } = useFetchData('https://api.example.com/user/profile');
const [storedUserData, setStoredUserData] = useLocalStorage('userProfile', null);
useEffect(() => {
if (userData) {
setStoredUserData(userData);
}
}, [userData, setStoredUserData]);
if (loading) {
return Ladataan käyttäjäprofiilia...
;
}
if (error) {
return Virhe käyttäjäprofiilin haussa: {error.message}
;
}
if (!userData && !storedUserData) {
return Käyttäjätietoja ei saatavilla.
;
}
const userToDisplay = storedUserData || userData;
return (
Käyttäjäprofiili
Nimi: {userToDisplay.name}
Sähköposti: {userToDisplay.email}
);
}
export default UserProfile;
Tässä esimerkissä olemme erottaneet datan hakulogiikan ja paikalliseen tallennustilaan tallentamisen logiikan kahteen erilliseen custom-hookiin. UserProfile
-komponentti sitten koostaa nämä hookit saavuttaakseen halutun toiminnallisuuden. Tämä lähestymistapa tekee koodista modulaarisempaa, uudelleenkäytettävämpää ja helpommin testattavaa.
Edistyneet esimerkit: Monimutkaisten efektien orkestrointi
Efektien koostaminen on entistäkin tehokkaampaa monimutkaisempien skenaarioiden käsittelyssä. Tutustutaan joihinkin edistyneisiin esimerkkeihin.
1. Tilausten ja tapahtumankuuntelijoiden hallinta
Harkitse tilannetta, jossa sinun on tilattava WebSocket-yhteys ja kuunneltava tiettyjä tapahtumia. Sinun on myös hoidettava siivous, kun komponentti poistetaan. Näin voit käyttää efektien koostamista tämän hallintaan:
a. useWebSocket
-hookin luominen
Tämä hook muodostaa WebSocket-yhteyden ja hoitaa uudelleenyhdistämislogiikan.
import { useState, useEffect, useRef } from 'react';
function useWebSocket(url) {
const [socket, setSocket] = useState(null);
const [isConnected, setIsConnected] = useState(false);
const retryCount = useRef(0);
useEffect(() => {
const connect = () => {
const newSocket = new WebSocket(url);
newSocket.onopen = () => {
console.log('WebSocket connected');
setIsConnected(true);
retryCount.current = 0;
};
newSocket.onclose = () => {
console.log('WebSocket disconnected');
setIsConnected(false);
// Eksponentiaalinen viive uudelleenyhdistämisessä
const timeout = Math.min(3000 * Math.pow(2, retryCount.current), 60000);
retryCount.current++;
console.log(`Reconnecting in ${timeout/1000} seconds...`);
setTimeout(connect, timeout);
};
newSocket.onerror = (error) => {
console.error('WebSocket error:', error);
};
setSocket(newSocket);
};
connect();
return () => {
if (socket) {
socket.close();
}
};
}, [url]);
return { socket, isConnected };
}
export default useWebSocket;
b. useEventListener
-hookin luominen
Tämä hook antaa sinun helposti kuunnella tiettyjä tapahtumia WebSocketissa.
import { useEffect } from 'react';
function useEventListener(socket, eventName, handler) {
useEffect(() => {
if (!socket) return;
const listener = (event) => handler(event);
socket.addEventListener(eventName, listener);
return () => {
socket.removeEventListener(eventName, listener);
};
}, [socket, eventName, handler]);
}
export default useEventListener;
c. Hookien koostaminen komponentissa
import React, { useState } from 'react';
import useWebSocket from './useWebSocket';
import useEventListener from './useEventListener';
function WebSocketComponent() {
const { socket, isConnected } = useWebSocket('wss://echo.websocket.events');
const [message, setMessage] = useState('');
const [receivedMessages, setReceivedMessages] = useState([]);
useEventListener(socket, 'message', (event) => {
setReceivedMessages((prevMessages) => [...prevMessages, event.data]);
});
const sendMessage = () => {
if (socket && isConnected) {
socket.send(message);
setMessage('');
}
};
return (
WebSocket-esimerkki
Yhteyden tila: {isConnected ? 'Yhdistetty' : 'Yhteys katkaistu'}
setMessage(e.target.value)}
placeholder="Kirjoita viesti"
/>
Vastaanotetut viestit:
{receivedMessages.map((msg, index) => (
- {msg}
))}
);
}
export default WebSocketComponent;
Tässä esimerkissä useWebSocket
hallitsee WebSocket-yhteyttä, mukaan lukien uudelleenyhdistämislogiikan, kun taas useEventListener
tarjoaa siistin tavan tilata tiettyjä tapahtumia. WebSocketComponent
koostaa nämä hookit luodakseen täysin toimivan WebSocket-asiakasohjelman.
2. Riippuvuuksia sisältävien asynkronisten operaatioiden orkestrointi
Joskus efektit on käynnistettävä tietyssä järjestyksessä tai tiettyjen riippuvuuksien perusteella. Oletetaan, että sinun on haettava käyttäjätiedot, sitten haettava heidän julkaisunsa käyttäjätunnuksen perusteella ja sitten päivitettävä käyttöliittymä. Voit käyttää efektien koostamista näiden asynkronisten operaatioiden orkestrointiin.
a. useUserData
-hookin luominen
Tämä hook hakee käyttäjätietoja.
import { useState, useEffect } from 'react';
function useUserData(userId) {
const [userData, setUserData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const json = await response.json();
setUserData(json);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, [userId]);
return { userData, loading, error };
}
export default useUserData;
b. useUserPosts
-hookin luominen
Tämä hook hakee käyttäjän julkaisuja käyttäjätunnuksen perusteella.
import { useState, useEffect } from 'react';
function useUserPosts(userId) {
const [userPosts, setUserPosts] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
if (!userId) {
setUserPosts(null);
setLoading(false);
return;
}
const fetchPosts = async () => {
try {
const response = await fetch(`https://api.example.com/users/${userId}/posts`);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const json = await response.json();
setUserPosts(json);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchPosts();
}, [userId]);
return { userPosts, loading, error };
}
export default useUserPosts;
c. Hookien koostaminen komponentissa
import React, { useState } from 'react';
import useUserData from './useUserData';
import useUserPosts from './useUserPosts';
function UserProfileWithPosts() {
const [userId, setUserId] = useState(1); // Aloita oletuskäyttäjätunnuksella
const { userData, loading: userLoading, error: userError } = useUserData(userId);
const { userPosts, loading: postsLoading, error: postsError } = useUserPosts(userId);
return (
Käyttäjäprofiili ja julkaisut
setUserId(parseInt(e.target.value, 10))}
/>
{userLoading ? Ladataan käyttäjätietoja...
: null}
{userError ? Virhe käyttäjätietojen latauksessa: {userError.message}
: null}
{userData ? (
Käyttäjän tiedot
Nimi: {userData.name}
Sähköposti: {userData.email}
) : null}
{postsLoading ? Ladataan käyttäjän julkaisuja...
: null}
{postsError ? Virhe käyttäjän julkaisujen latauksessa: {postsError.message}
: null}
{userPosts ? (
Käyttäjän julkaisut
{userPosts.map((post) => (
- {post.title}
))}
) : null}
);
}
export default UserProfileWithPosts;
Tässä esimerkissä useUserPosts
riippuu userId
:stä. Hook hakee julkaisuja vain, kun voimassa oleva userId
on saatavilla. Tämä varmistaa, että efektit käynnistyvät oikeassa järjestyksessä ja että käyttöliittymä päivittyy vastaavasti.
Parhaat käytännöt efektien koostamiseen
Jotta saisit kaiken hyödyn irti efektien koostamisesta, harkitse seuraavia parhaita käytäntöjä:
- Yhden vastuun periaate: Jokaisella custom-hookilla tulisi olla yksi, selkeästi määritelty vastuu.
- Kuvailevat nimet: Käytä kuvailevia nimiä custom-hookeillesi, jotta niiden tarkoitus on selkeä.
- Riippuvuustaulukot: Hallitse huolellisesti
useEffect
-kutsujesi riippuvuustaulukoita välttääksesi turhia uudelleenrenderöintejä tai äärettömiä silmukoita. - Testaaminen: Kirjoita yksikkötestejä custom-hookeillesi varmistaaksesi, että ne toimivat odotetusti.
- Dokumentaatio: Dokumentoi custom-hookisi, jotta ne ovat helpommin ymmärrettävissä ja uudelleenkäytettävissä.
- Vältä yliabstrahointia: Älä ylisuunnittele custom-hookejasi. Pidä ne yksinkertaisina ja kohdennettuina.
- Huomioi virheidenkäsittely: Toteuta vankka virheidenkäsittely custom-hookeissasi käsitelläksesi odottamattomia tilanteita sulavasti.
Globaalit huomiot
Kun kehität React-sovelluksia globaalille yleisölle, pidä mielessä seuraavat seikat:
- Kansainvälistäminen (i18n): Käytä kirjastoa kuten
react-intl
taii18next
tukeaksesi useita kieliä. - Lokalisointi (l10n): Mukauta sovelluksesi erilaisiin alueellisiin mieltymyksiin, kuten päivämäärä- ja numeromuotoihin.
- Saavutettavuus (a11y): Varmista, että sovelluksesi on saavutettavissa vammaisille käyttäjille noudattamalla WCAG-ohjeita.
- Suorituskyky: Optimoi sovelluksesi eri verkkoyhteyksille ja laiteominaisuuksille. Harkitse tekniikoita, kuten koodin jakamista ja laiskaa lataamista.
- Sisällönjakeluverkot (CDN): Käytä CDN:ää toimittaaksesi sovelluksesi resurssit palvelimilta, jotka sijaitsevat lähempänä käyttäjiäsi, vähentäen viivettä ja parantaen suorituskykyä.
- Aikavyöhykkeet: Kun käsittelet päivämääriä ja aikoja, ole tietoinen eri aikavyöhykkeistä ja käytä sopivia kirjastoja, kuten
moment-timezone
taidate-fns-timezone
.
Esimerkki: Kansainvälistetty päivämäärän muotoilu
import { useIntl, FormattedDate } from 'react-intl';
function MyComponent() {
const intl = useIntl();
const now = new Date();
return (
Nykyinen päivämäärä:
Nykyinen päivämäärä (saksa):
);
}
export default MyComponent;
Yhteenveto
Efektien koostaminen on tehokas tekniikka monimutkaisten sivuvaikutusten hallintaan React-sovelluksissa. Pilkkomalla suuret efektit pienempiin, uudelleenkäytettäviin custom-hookeihin voit parantaa koodin uudelleenkäytettävyyttä, lisätä luettavuutta, yksinkertaistaa testaamista ja vähentää yleistä monimutkaisuutta. Ota efektien koostaminen käyttöön luodaksesi puhtaampia, ylläpidettävämpiä ja skaalautuvampia React-sovelluksia globaalille yleisölle.