Optymalizacja efektów React z useEventEffect
Zespół React pracuje nad useEventEffect
, który pomaga w refaktoryzacji efektów poprzez redukcję ich zależności i poprawę struktury logicznej poprzez wyraźne rozróżnienie zdarzeń od efektów. Ta funkcja jest w fazie eksperymentalnej, więc nie używaj jej jeszcze w swoich aplikacjach produkcyjnych!
Po przeczytaniu artykułu możesz zapoznać się z małym demo, które przygotowałem jako dodatek do poniższych przykładów. Dodatkowo, gorąco polecam przeczytanie oficjalnego artykułu na blogu React na temat useEventEffect
, aby głębiej zrozumieć ten temat.
Kiedy go używać
Kiedy useEventEffect
może być przydatny? Pomaga, gdy musimy zaktualizować efekt, aby bezpośrednio zmienić zachowanie funkcji, które musi być zsynchronizowane z stanem i nie może istnieć poza efektem. Na przykład:
- Połączenie WebSocket
- Polling
setInterval
setTimeout
Przykłady
const [intervalMs, setIntervalMs] = useState(1000)
useEffect(() => {
const intervalId = setInterval(callback, intervalMs)
return () => clearInterval(intervalId)
}, [intervalMs])
Za każdym razem, gdy intervalMs
się zmienia, musimy zaktualizować efekt, aby dostosować się do nowej wartości. Ale co się dzieje, gdy mamy więcej zależności, a niektóre z nich są używane w callback()
? Komponent niepotrzebnie ponownie uruchamia efekt, jeśli zależność nie wpływa bezpośrednio na setInterval
.
const [intervalMs, setIntervalMs] = useState(1000)
const [value, setValue] = useState('Hello')
useEffect(() => {
const intervalId = setInterval(() => {
displayMessage(value)
}, intervalMs)
return () => clearInterval(intervalId)
}, [intervalMs, value])
Używając useEffectEvent
, możesz zredukować zależności i zmniejszyć niepotrzebne ponowne uruchamianie efektów:
const [intervalMs, setIntervalMs] = useState(1000)
const [value, setValue] = useState('Hello')
const displayMessage = useEffectEvent(() => {
displayMessage(value)
})
useEffect(() => {
const intervalId = setInterval(displayMessage, intervalMs)
return () => clearInterval(intervalId)
}, [intervalMs])
Dzięki useEffectEvent
możesz być pewien, że odniesienia do zewnętrznych wartości są zawsze aktualne.
Ostatni przykład, który chciałbym przedstawić, to co się dzieje, gdy callback
interwału musi korzystać z wartości z zależności efektu:
const [intervalMs, setIntervalMs] = useState(1000)
const [value, setValue] = useState('Hello')
const displayMessage = useEffectEvent((redirectedToUrl) => {
displayMessage(value, redirectedToUrl)
})
useEffect(() => {
redirect(url);
const intervalId = setInterval(() => displayMessage(url), intervalMs)
return () => clearInterval(intervalId)
}, [url, intervalMs])
Preferowanym podejściem jest przekazywanie zależności bezpośrednio do zdarzeń efektów dla lepszej wiarygodności i czytelności. Jest to bardziej wiarygodne, ponieważ jeśli url
zostanie przypadkowo lub celowo usunięty, otrzymasz ostrzeżenie, że displayMessage
wymaga aktualizacji lub refaktoryzacji. Dodatkowo, url
jest zawsze zsynchronizowany z najnowszym uruchomieniem efektu. Jest to bardziej czytelne, ponieważ wyraźnie wymaga argumentów funkcji, co ułatwia innym programistom zrozumienie, jak to działa i jak to utrzymać.
Bibliografia
- Oficjalna dokumentacja React - Separating Events from Effects
- Demo - Moje repozytorium na GitHubie