Poznajemy kilka custom hooks z internetu, dzięki którym lepiej zrozumiemy useEffect, który znamy już dobrze i niewiele nam do nauki w tym temacie zostało.
Ok, hook useEffectOnce:
import { useEffect } from "react"
export default function useEffectOnce(cb) {
useEffect(cb, [])
}
Pusta tablica zależności – zostanie odpalony 1 raz. Użycie:
import { useState } from "react"
import useEffectOnce from "./useEffectOnce"
export default function EffectOnceComponent() {
const [count, setCount] = useState(0)
useEffectOnce(() => alert("Hi"))
return (
<>
<div>{count}</div>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
</>
)
}
Oczywiście to, co w callbacku nie może polegać na czymkolwiek reaktywnym (znamy już definicję reaktywności).
Btw, WebDevSimplified te hooki stworzył i trzyma na swoim Githubie, polecam poczytać. Ok, useUpdateEffect:
import { useEffect, useRef } from "react"
export default function useUpdateEffect(callback, dependencies) {
const firstRenderRef = useRef(true)
useEffect(() => {
if (firstRenderRef.current) {
firstRenderRef.current = false
return
}
return callback()
}, dependencies)
}
Czyli:
- przekazujemy callback i zależności
- przy mount ref ustawione na true
- przy useEffect odpalonym po raz pierwszy mamy ref na true
- zatem ustawiamy ref na false i wychodzimy
- przy kolejnych zawołaniach wywołanych przez update, ale nie mount, nasz kod wywoła callback
Oto przykład użycia:
import { useState } from "react"
import useUpdateEffect from "./useUpdateEffect"
export default function UpdateEffectComponent() {
const [count, setCount] = useState(10)
useUpdateEffect(() => alert(count), [count])
return (
<div>
<div>{count}</div>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
</div>
)
}
Ok, a teraz useEventListener:
import { useEffect, useRef } from "react"
export default function useEventListener(
eventType,
callback,
element = window
) {
const callbackRef = useRef(callback)
useEffect(() => {
callbackRef.current = callback
}, [callback])
useEffect(() => {
if (element == null) return
const handler = e => callbackRef.current(e)
element.addEventListener(eventType, handler)
return () => element.removeEventListener(eventType, handler)
}, [eventType, element])
}
Ok, czyli:
- do hooka przekazujemy eventType, callback i element (domyślnie będzie window)
- przy mount tworzymy ref do callbacka
- mamy useEffect, który patrzy, czy nam się callback nie zmienił i ustawia ref na nowy callback
- mamy useEffect, który słucha na zmianę eventType oraz element
- Jeżeli element jest nullem to brutalny return
- Tworzymy handler, którym jest callback z przekazanym eventem
- dodajemy do element event listener określonego typu i z handlerem, który wywołuje callback przekazując event
- w cleanup czyścimy event listener
Przykład użycia:
import { useState } from "react"
import useEventListener from "./useEventListener"
export default function EventListenerComponent() {
const [key, setKey] = useState("")
useEventListener("keydown", e => {
setKey(e.key)
})
return <div>Last Key: {key}</div>
}
Więcej Reacta niedługo, przeanalizujmy to i szukajmy w internecie dobrych custom hooków.