реагировать на хуки useEffect () очистка только для componentWillUnmount?


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() ввод имени.

Я хочу сделать так, чтобы компонент поддерживал как componentDidUpdate()ввод имени, так и componentWillUnmount(). (ведение журнала `` очищено '' только для момента размонтирования компонента)


4
У вас может быть 2 отдельных эффекта. Один, которому передается массив, содержащий usernameв нем второй аргумент, а другой - пустой массив, в качестве второго аргумента.
Tholle 06

@Tholle Вы имеете в виду, что мне нужно сделать 2 отдельных метода useEffect ()?
koo

1
Да, это один из способов сделать это.
Толле 06

1
@Tholle Я думал, что это будет отменено последним методом useEffect (). Я буду стараться. Спасибо
koo

2
Большой! Пожалуйста. Это зависит от того, что должна делать очистка. 2 отдельных эффекта - неплохое решение.
Tholle 06

Ответы:


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 я не вижу этого триггера.
Фабиан Бослер,

121

вы можете использовать более одного 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
В чем разница между первым и последним useEffect, первый useEffect будет вызываться на willmount или didmount , последний useEffect был возвращен функцией обратного вызова с пустым массивом, почему? не могли бы вы подробно рассказать о каждом из вариантов использования useEffect, когда и как мы можем его использовать?
Силуверу Киран Кумар 02

4
@siluverukirankumar Возвращаемое значение (функция) обратного вызова - это то, что вызывается при уничтожении (событие размонтирования). Вот почему последний пример - HOC, немедленно возвращающий функцию. Второй параметр - это место, где React будет искать изменения, чтобы повторно запустить этот хук. Когда это пустой массив, он запускается только один раз.
Георгий

3
Спасибо, @Georgy получил это в последний раз, когда useEffect возвращает обратный вызов, который четко не виден
siluveru kiran kumar

2
Итак, если вы создаете ловушку useEffect, и она возвращает функцию ... тогда код перед возвращенной функцией запускается как componentDidMount ... и код в возвращаемой функции вызывается для componentWillUnmount? Это немного сбивает с толку, поэтому убедитесь, что я правильно понимаю. useEffect (() => {// код для запуска при монтировании ... return () => {// код для запуска размонтирования}}) Правильно?
Maiya

Предлагаю прочитать overrected.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.