reaguj na haki czyszczenie useEffect () tylko dla componentWillUnmount?


94

Pozwólcie, że wyjaśnię wynik tego kodu, aby łatwo zadać mój problem.

const ForExample = () => {
    const [name, setName] = useState('');
    const [username, setUsername] = useState('');

    useEffect(() => {
        console.log('effect');
        console.log({
            name,
            username
        });

        return () => {
            console.log('cleaned up');
            console.log({
                name,
                username
            });
        };
    }, [username]);

    const handleName = e => {
        const { value } = e.target;

        setName(value);
    };

    const handleUsername = e => {
        const { value } = e.target;

        setUsername(value);
    };

    return (
        <div>
            <div>
                <input value={name} onChange={handleName} />
                <input value={username} onChange={handleUsername} />
            </div>
            <div>
                <div>
                    <span>{name}</span>
                </div>
                <div>
                    <span>{username}</span>
                </div>
            </div>
        </div>
    );
};

Po ForExample componentzamontowaniu zostanie zarejestrowany „efekt”. Jest to związane z componentDidMount().

Za każdym razem, gdy zmienię dane wejściowe, zarówno „efekt”, jak i „wyczyszczony” będą rejestrowane. I odwrotnie, żadna wiadomość nie zostanie zarejestrowana za każdym razem, gdy zmienię nazwę użytkownika, ponieważ dodałem [username]drugi parametr useEffect(). Jest to związane zcomponentDidUpdate()

Na koniec, gdy ForExample componentodmontowanie zostanie zapisane, zostanie zapisane polecenie „wyczyszczone”. Jest to związane z componentWillUnmount().

Wszyscy to wiemy.

Podsumowując, funkcja „wyczyszczona” jest wywoływana za każdym razem, gdy komponent jest ponownie renderowany (obejmuje odmontowanie)

Jeśli chcę, aby ten komponent rejestrował się „wyczyszczony” tylko na moment, w którym jest odmontowywany, wystarczy zmienić drugi parametr useEffect()na [].

Ale jeśli zmienię [username]na [], ForExample componentnie implementuje już componentDidUpdate()danych wejściowych dla nazwy.

Chcę to zrobić, aby komponent obsługiwał zarówno componentDidUpdate()tylko wprowadzanie nazwy, jak i componentWillUnmount(). (rejestrowanie `` wyczyszczone '' tylko na moment, w którym komponent jest odmontowywany)


4
Możesz mieć 2 oddzielne efekty. Jedna, której podano tablicę, usernamew której jako drugi argument, i jedna, której jako drugi argument podano pustą tablicę.
— Tholle

@Tholle Czy masz na myśli 2 oddzielne metody useEffect ()?
— koo

1
Tak, to jeden ze sposobów.
— Tholle,

1
@Tholle Myślałem, że zostanie to zastąpione przez ostatnią metodę useEffect (). Spróbuję. Dzięki
— koo

2
Świetny! Nie ma za co. To zależy od tego, co powinno zrobić czyszczenie. 2 oddzielne efekty nie są złym rozwiązaniem.
— Tholle,

Odpowiedzi:


87

Ponieważ czyszczenie nie jest zależne od opcji username, możesz umieścić czyszczenie w oddzielnym, useEffectktóry otrzymuje pustą tablicę jako drugi argument.

Przykład

const { useState, useEffect } = React;

const ForExample = () => {
  const [name, setName] = useState("");
  const [username, setUsername] = useState("");

  useEffect(
    () => {
      console.log("effect");
    },
    [username]
  );

  useEffect(() => {
    return () => {
      console.log("cleaned up");
    };
  }, []);

  const handleName = e => {
    const { value } = e.target;

    setName(value);
  };

  const handleUsername = e => {
    const { value } = e.target;

    setUsername(value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={handleName} />
        <input value={username} onChange={handleUsername} />
      </div>
      <div>
        <div>
          <span>{name}</span>
        </div>
        <div>
          <span>{username}</span>
        </div>
      </div>
    </div>
  );
};

function App() {
  const [shouldRender, setShouldRender] = useState(true);

  useEffect(() => {
    setTimeout(() => {
      setShouldRender(false);
    }, 5000);
  }, []);

  return shouldRender ? <ForExample /> : null;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>


ładny i czysty przykład. Zastanawiam się jednak. Czy mogę w jakiś sposób wywołać efekt użycia w zmienionej nawigacji, czy też będę musiał przesunąć go w górę w drzewie komponentów? Ponieważ podczas wklejania „wyczyszczonego” useEffect nie widzę tego wyzwalacza.
— Fabian Bosler

121

możesz użyć więcej niż jednego useEffect

na przykład, jeśli moja zmienna to data1, mogę użyć tego wszystkiego w moim komponencie

useEffect( () => console.log("mount"), [] );
useEffect( () => console.log("will update data1"), [ data1 ] );
useEffect( () => console.log("will update any") );
useEffect( () => () => console.log("will update data1 or unmount"), [ data1 ] );
useEffect( () => () => console.log("unmount"), [] );

5
jaka jest różnica między pierwszym a ostatnim efektem useEffect, najpierw funkcja useEffect zostanie wywołana na willmount lub didmount , ostatnio zwrócono funkcję wywołania zwrotnego useEffect z pustą tablicą dlaczego? czy mógłbyś szczegółowo opisać przypadki użycia useEffect, kiedy i jak możemy ich używać?
— siluveru kiran kumar

4
@siluverukirankumar Wartość zwracana (funkcja) wywołania zwrotnego jest tym, co jest wywoływane podczas niszczenia (zdarzenie odmontowania). Dlatego ostatnim przykładem jest HOC, natychmiast zwracająca funkcję. Drugi parametr to miejsce, w którym React szukałby zmian, aby ponownie uruchomić to podpięcie. Gdy jest to pusta tablica, będzie działać tylko raz.
— Georgy

3
Dzięki @Georgy dostałem to ostatnie użycieEffect zwraca oddzwonienie niewidoczne wyraźnie
— siluveru kiran kumar

2
Tak więc, jeśli utworzysz punkt zaczepienia useEffect i zwróci on funkcję ... to kod przed zwróconą funkcją zostanie uruchomiony jako componentDidMount ... a kod w funkcji zwróconej zostanie wywołany dla elementu componentWillUnmount? To trochę zagmatwane, więc upewnij się, że dobrze rozumiem. useEffect (() => {// kod do uruchomienia po zamontowaniu ... return () => {// kod do uruchomienia demontażu}}) Zgadza się?
— Maiya

Proponuję przeczytać overreacted.io/a-complete-guide-to-useeffect Myślenie o hakach w cyklach życia nie jest takie słodkie
— moto

2
function LegoComponent() {

  const [lego, setLegos] = React.useState([])

  React.useEffect(() => {
    let isSubscribed = true
    fetchLegos().then( legos=> {
      if (isSubscribed) {
        setLegos(legos)
      }
    })
    return () => isSubscribed = false
  }, []);

  return (
    <ul>
    {legos.map(lego=> <li>{lego}</li>)}
    </ul>
  )
}

W powyższym kodzie funkcja fetchLegos zwraca obietnicę. Możemy „anulować” obietnicę, posiadając warunek w zakresie useEffect, uniemożliwiający aplikacji ustawienie stanu po odmontowaniu komponentu.

Ostrzeżenie: nie można przeprowadzić aktualizacji stanu React na niezmontowanym komponencie. Nie można tego robić, ale wskazuje na wyciek pamięci w aplikacji. Aby to naprawić, anuluj wszystkie subskrypcje i zadania asynchroniczne w funkcji czyszczenia useEffect.


1

Zamiast tworzyć zbyt wiele skomplikowanych funkcji i metod, tworzę odbiornik zdarzeń i automatycznie wykonuję montowanie i odmontowywanie, bez martwienia się o zrobienie tego ręcznie. Oto przykład.

//componentDidMount
useEffect( () => {

    window.addEventListener("load",  pageLoad);

    //component will unmount
    return () => {
       
        window.removeEventListener("load", pageLoad);
    }

 });

teraz, gdy ta część jest skończona, po prostu uruchamiam wszystko, co chcę, z funkcji pageLoad w ten sposób.

const pageLoad = () =>{
console.log(I was mounted and unmounted automatically :D)}

0

useEffect są izolowane we własnym zakresie i odpowiednio renderowane. Obraz z https://reactjs.org/docs/hooks-custom.html

wprowadź opis obrazu tutaj


Link do rozwiązania jest mile widziany, ale upewnij się, że Twoja odpowiedź jest przydatna bez niego: dodaj kontekst wokół linku, aby inni użytkownicy mieli pojęcie, co to jest i dlaczego się tam znajduje, a następnie zacytuj najbardziej odpowiednią część strony, którą podałeś. ponowne łącze w przypadku, gdy strona docelowa jest niedostępna. Odpowiedzi, które są niewiele więcej niż linkiem, mogą zostać usunięte .
— Богдан Опир
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.