Optymalizacja efektów React z useEventEffect

  • javascript
  • react

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