Na przykładzie kodu znalezionego w internecie poznajemy jak działa useEffect razem z asynchronicznymi funkcjami. Do dzieła.
Myślę, że najlepiej będzie to przedstawić kawałkami:
export default function App() {
const [amount, setAmount] = useState(1);
//(...)
useEffect(
//(...)
[amount, fromCur, toCur]
);
return (
<div>
<input
type="text"
value={amount}
onChange={(e) => setAmount(Number(e.target.value))}
disabled={isLoading}
/>
//(...)
Czyli tak:
- Pod App mamy zmienne stanowe tego RFC
- W useEffect będzie definicja funkcji async robiącej await na fetch api i wywołanie tej funkcji
- W Returnie mamy JSX
Na razie widzimy amount i odpowiadający mu input. Typu tekstowego, zatem e.target.value musimy konwertować do number. Disabled bindowane do zmiennej isLoading, na razie jej nie widzimy.
Pozostałe zmienne powiązane z markupem JSX:
const [fromCur, setFromCur] = useState("EUR");
const [toCur, setToCur] = useState("USD");
const [converted, setConverted] = useState("");
const [isLoading, setIsLoading] = useState(false);
//(...)
<select
value={fromCur}
onChange={(e) => setFromCur(e.target.value)}
disabled={isLoading}
>
<option value="USD">USD</option>
<option value="EUR">EUR</option>
<option value="CAD">CAD</option>
<option value="INR">INR</option>
</select>
<select
value={toCur}
onChange={(e) => setToCur(e.target.value)}
disabled={isLoading}
>
<option value="USD">USD</option>
<option value="EUR">EUR</option>
<option value="CAD">CAD</option>
<option value="INR">INR</option>
</select>
<p>
{converted} {toCur}
</p>
</div>
);
}
Jak widać nigdzie nie mamy ustawienia setIsLoading ani setConverted, te nasze inputy zmieniają tylko:
- Jaką liczbę konwertujemy
- Z jakiej waluty
- Na jaką walutę
Ustawienie loading na true oraz sama konwersja musi zatem odbywać się w useEffect. Tak ono wygląda:
useEffect(
function () {
async function convert() {
setIsLoading(true);
const res = await fetch(
`https://api.frankfurter.app/latest?amount=${amount}&from=${fromCur}&to=${toCur}`
);
const data = await res.json();
setConverted(data.rates[toCur]);
setIsLoading(false);
}
if (fromCur === toCur) return setConverted(amount);
convert();
},
[amount, fromCur, toCur]
);
Mamy w callbacku:
- Definicję async funkcji convert
- Ta funkcja ustawia isLoading na true
- Następnie robi res, na którym jest await fetch
- Następnie robi await na res.json (nowa składnia, kiedyś mieliśmy promise, then i tak dalej)
- Ustawia konwersję na to, co przyszło z api
- Ustawia ładowanie na false
- Poniżej definicji mamy sprawdzenie czy aby waluty nie są takie same i return plus ustawienie converted na to samo (np. 5 dolarów to… 5 dolarów) bez opóźnienia
- Jeżeli różnią się to wywołujemy funkcję convert, która jest asynchroniczna
- W zależnościach mamy amount, fromCur, toCur, nie wybieramy sobie zależności, to warto podkreślić, ale efekt chodzi gdy któraś się zmieni
Więcej Reacta niedługo…