React: Haki (hooks) na Reacta
Opublikowano sob 08 sierpnia 2020 w reactjs • 3 min read
Haki/Przyczepienia (hooks)
Hooki mogą być używane jedynie w komponentach funkcyjnych i pozwalają na przechowanie stanu pomiędzy kolejnymi wywołaniami funkcji zawartych w komponentach! Podstawowe dwa z nich pozwalają na wprowadzenie stanów (useState) podczas gdy inny pozwala na zarządzanie automatycznym zachowaniem się danego komponentu (useEffect) - kompensując brak funkcji znanych z komponentów klasowych jak componentDidMount(), componentDidUpdate() oraz componentWillUnmount(). Jednym z szybko zauważalnych efektów korzystania z komponentów funkcyjnych + hooków jest uproszczenie kodu. Hooki nie mogą znaleźć się w pętlach, funkcjach, ifach etc. i powinny być zadeklarowane w określonej kolejności (najlepiej jak najwcześniej)
Hooki zaimportować z biblioteki React podobnie jak Component w przypadku komponentów klasowych.
import React, {useState} from 'react';
Definiowanie stanu -> useState()
useState() - zwraca tablicę elementów (parę) - przy pomocy destrukturyzacji można "wyciągnąć" poszczególne elementy do zmiennych (co jest przyjętą praktyką). Istotną konwencją, o której warto w tym kontekście pamiętać jest to, że pierwsza zmienna przechowuje stan natomiast kolejna powinna odwoływać się do funkcji, która ma wpływ na zmianę stanu. Nazwa 2. elementu powinna powielać nazwę tej, która przechowuje stan ale poprzedza ją słowem 'set'. useState przyjmuje argument określający początkową właściwość stanu
const[stanu, funkcjaZmieniającaStan] = useState(początkowyStan)
const [state, setstate] = useState(initialState);
====== przykładowo =====
const [counter, setCounter] = useState(0)
Aby użyć analogii można stwierdzić, że useState() w funkcyjnym komponencie "zastępuje" z komponentu klasowego konstruktor stanu oraz setState() (setState() => setWybranaNazwaFunkcjiModyfikatora() np. setCounter())
Przykład
const Counter = () => {
const[counter, SetCounter] = useState(0)
const increment = () => (setCounter(prevCounter=> prevCounter +1)
return <button onClick={increment}>{counter}</button>
}
Obsługa efektów ubocznych useEffect()
useEffect() ma mieć wpływ na kod z poza zakresu wywoływanej funkcji lub inaczej rzecz ujmując odpowiada za wykonywanie efektów ubocznych w komponentach funkcyjnych. Hook useEffect() pozwala na ustawienie zależności wywoływania się konkretnej zawartej w nim funkcji oraz na zwolnienie jej zasobów - jednak nie w każdej sytuacji jest to wymagane.
//wywoła się podczas każdorazowego renderowania komponentu
useEffect(() => {
console.log('Komponent zamontowany')
})
Podstawowy schemat prezentuje się następująco. Warto zwrócić uwagę na tablicę kończącą wyrażenie (input) w to miejsce można wpisać zależności, których zmiana spowoduje wywołanie się funkcji - brak elementów oznacza, że funkcja powinna wywołać się tylko raz, podczas pierwszego renderowania elementu
useEffect(() => {
effect
return () => {
cleanup
};
}, [input]);
Przykład 1
// uruchamia się tylko raz ponieważ w arg. brak info o tym by się uruchamiał ponownie
// co 1 sekundę dodaj kropkę do stringa zawartego w stanie >>message<<
useEffect(() => {
const intervalId = setInterval(() => {
setMessage((prev)=> prev+'.');
}, 1000);
return () => { // czyszczenie interwału/pamięci
clearInterval(intervalId)
};
}, []);
Przykład 2
// uruchamia się za każdym razem jak counter ulegnie zmianie
useEffect(() => {
document.title = `Clicked:${counter}`
},[counter]) // kiedy wywołać? - jak counter ulegnie zmianie
Przykład komponentu funkcyjnego korzystającego z hooków
import React, {useState, useEffect} from "react";
import ReactDOM from "react-dom";
const ShowInfo = ({info}) => {
return <h1>{info}</h1>
}
const PropsToState = ({text}) => {
const [message, setMessage] = useState(text)
const [click, setClick] = useState(0)
useEffect(() => {
const intervalId = setInterval(() => {
setMessage((prev)=> prev+'.');
}, 1000);
return () => {
clearInterval(intervalId)
};
}, []);
useEffect(() => {
document.title = `Clicked:${click}`
},[click])
const clicked = () => (setClick(prev=>prev+1))
return (
<>
<ShowInfo info={message}/>
<h2>Clicked {click} times</h2>
<button onClick={clicked}>Clicke Me</button>
)
}
ReactDOM.render(
<PropsToState text='Wielokropek'/>,
document.getElementById("app")
);
Własne hooki
Haki to nic innego jak zamknięty blok kodu, który można wielokrotnie wykorzystać. Podstawową zasadą/konwencją hooka jest to, że zaczyna się od słowa kluczowego use
i wywołuje inne hooki innymi słowy ma on za zadanie wydzielenie logiki wykorzystującej podstaowe hooki, dodatkowo można blok kodu skonstruować w ten sposób aby przyjmował dodatkowe argumenty (w zależności od zapotrzebowania)
Przykład hooka który obsługuje wartość wpisaną do inputa będącego częścią formularza (źródło przykładu: Create a Custom React Hook to Handle Form Fields)
import { useState } from "react";
export function useFormFields(initialState) {
const [fields, setValues] = useState(initialState);
return [
fields,
function(event) {
setValues({
...fields,
[event.target.id]: event.target.value
});
}
];
}
Przykładowe użycie wygląda w następujący sposóbu
import { useFormFields } from "../ścieżka/hooksLib";
[...] === deklaracja stanu ===
const [fields, handleFieldChange] = useFormFields({
email: "",
password: ""
});
[....] === odowłoanie się do funkcji zmieniającej stan ====
<FormControl
type="password"
value={fields.password}
onChange={handleFieldChange}
/>
[więcej na ten temat w kontekście opisywania formularzy]
Źródła:
React Hooks — wprowadzenie i motywacja
React Hooks: useState, czyli stan w komponentach funkcyjnych
Clean Up Async Requests in useEffect
Hooks
[PL]React Hooks: Wstęp + useState