гачки реакцій useEffect () очищення лише для компонентаWillUnmount?


94

Дозвольте мені пояснити результат цього коду за те, що я легко поставив своє питання.

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>
    );
};

Коли ForExample componentмонтується, буде записано "ефект". Це пов'язано з componentDidMount().

І щоразу, коли я зміню введення імені, реєструються як „ефект“, так і „очищення“. Навпаки, жодне повідомлення не реєструватиметься, коли я зміню введення імені користувача, оскільки я додав [username]до другого параметра useEffect(). Це пов'язано зcomponentDidUpdate()

Нарешті, коли ForExample componentдемонтується, буде очищено журнал. Це пов'язано з componentWillUnmount().

Ми всі це знаємо.

Підводячи підсумок, "очищення" викликається щоразу, коли компонент рендерується (включає демонтаж)

Якщо я хочу зробити цей компонент журналом "очищеним" лише на той момент, коли він буде відключений, мені просто потрібно змінити другий параметр useEffect()на [].

Але якщо я змінив [username]на [], ForExample componentбільше не реалізовує componentDidUpdate()введення імені for.

Що я хочу зробити, це зробити компонент підтримкою як componentDidUpdate()для введення імені, так і componentWillUnmount(). (реєстрація "очищена" лише на той момент, коли компонент демонтується)


4
Ви можете мати 2 окремі ефекти. Такий, якому надано масив із usernameдругим аргументом, а другий - порожнім масивом як другий аргумент.
Tholle

@Tholle Ви маєте на увазі, що я маю зробити два окремі методи useEffect ()?
Ка

1
Так, це один із способів це зробити.
Tholle

1
@Tholle Я думав, що це буде замінено останнім методом useEffect (). Я спробую. Спасибі
Koo

2
Чудово! Ласкаво просимо. Це залежить від того, що слід робити прибирання. 2 окремі ефекти - це не погане рішення.
Tholle

Відповіді:


88

Оскільки очищення не залежить від username, ви можете помістити очищення в окремий, useEffectякий отримує порожній масив як другий аргумент.

Приклад

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>


приємний і чистий приклад. Мені цікаво. Чи можу я якось викликати ефект використання на зміненій навігації, або мені доведеться переміщати його вгору в дереві компонентів? Оскільки, просто вставляючи ваш "очищений" useEffect, я не бачу цей тригер.
Фабіан Бослер

122

ви можете використовувати більше одного useEffect

наприклад, якщо моя змінна data1, я можу використовувати все це у своєму компоненті

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
яка різниця між першим та останнім useEffects, перший useEffect буде викликаний на willmount або didmount , останній useEffect повернуто функцію зворотного виклику з порожнім масивом чому? чи не могли б Ви детально описати кожне використанняEffect випадків використання, коли і як ми можемо використовувати?
siluveru kiran kumar

4
@siluverukirankumar Повернене значення (функція) зворотного виклику - це те, що викликається при знищенні (подія відключення). Ось чому останній приклад - це HOC, що негайно повертає функцію. Другий параметр - це те, де React шукатиме змін для повторного запуску цього хука. Коли це порожній масив, він запускається лише один раз.
Георгій

3
Завдяки @Georgy отримав його останній useEffect повертається зворотний виклик не бачив ясно
siluveru Кіран Кумар

2
Отже, якщо ви робите хук useEffect, і він повертає функцію .., то код перед функцією, що повертається, виконується як componentDidMount ... і код у функції, що повертається, викликається для componentWillUnmount? Це трохи заплутано, тому переконайтесь, що я правильно розумію. useEffect (() => {// код для запуску на монтуванні ... return () => {// код для запуску з демонтажу}}) Чи правильно?
Майя

Я пропоную прочитати overreacted.io/a-complete-guide-to-useeffect Думати про гачки в життєвих циклах насправді не так солодко
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>
  )
}

У наведеному вище коді функція fetchLegos повертає обіцянку. Ми можемо „скасувати” обіцянку, встановивши умову в обсязі useEffect, не дозволяючи програмі встановлювати стан після відключення компонента.

Попередження: Не вдається виконати оновлення стану React для немонтованого компонента. Це заборона, але це свідчить про витік пам’яті у вашому додатку. Щоб виправити, скасуйте всі підписки та асинхронні завдання за допомогою функції очищення useEffect.


1

замість того, щоб створювати занадто багато складних функцій та методів, я роблю це, я створюю прослуховувач подій і автоматично виконую монтування та демонтаж для мене, не турбуючись про те, щоб зробити це вручну. Ось приклад.

//componentDidMount
useEffect( () => {

    window.addEventListener("load",  pageLoad);

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

 });

Тепер, коли ця частина закінчена, я просто запускаю все, що завгодно, із функції pageLoad, як це.

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

0

useEffect виділяються в межах власного обсягу і отримують відповідний візуалізацію. Зображення з https://reactjs.org/docs/hooks-custom.html

введіть тут опис зображення


Посилання на рішення вітається, але будь ласка, переконайтеся, що ваша відповідь корисна без нього: додайте контекст навколо посилання, щоб ваші однодумці мали певне уявлення, що це таке і чому воно є, а потім цитуйте найбільш відповідну частину сторінки, яку ви хочете повторне посилання на випадок, якщо цільова сторінка буде недоступна. Відповіді, які є лише кількома посиланнями, можуть бути видалені .
Богдан Опир
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.