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

Позвольте мне объяснить результат этого кода, чтобы легко задать мою проблему.

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

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

        return () => {
            console.info('cleaned up');
            console.info({
                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(). (логирование "очищается" только на момент размонтирования компонента)

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

Tholle 06.03.2019 11:02

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

koo 06.03.2019 11:05

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

Tholle 06.03.2019 11:06

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

koo 06.03.2019 11:07

@ Толле Это работает. еще раз спасибо. Кстати, есть ли более красивый способ реализовать это? Такое ощущение, что мы дважды пишем одноимённые методы.

koo 06.03.2019 11:11

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

Tholle 06.03.2019 11:12

@Tholle для меня не работает, я работаю с редуксом, и у меня есть метод, который сбрасывает все данные, когда компонент выгружается, но у меня не работает, помогите......

Racal 07.08.2021 10:30

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

koo 19.08.2021 10:55

@koo я решил эту проблему, но мы можем подружиться на github. Спасибо.

Racal 21.08.2021 18:27
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
142
9
186 881
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

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

Пример

const { useState, useEffect } = React;

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

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

  useEffect(() => {
    return () => {
      console.info("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, я не вижу этого триггера.

Fabian Bosler 22.04.2020 13:06

Вы можете использовать более одного useEffect().

Например, если моя переменная data1, я могу использовать все это в своем компоненте:

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

в чем разница между первым и последним useEffects, первый useEffect будет вызываться для будетмонтировать или сделалмаунт, последний useEffect был возвращен функцией обратного вызова с пустым массивом, почему? Не могли бы вы уточнить каждый вариант использования useEffect, когда и как мы можем его использовать?

siluveru kiran kumar 02.08.2019 12:46

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

Georgy 28.08.2019 00:06

Спасибо, @Georgy понял, что последний useEffect возвращает обратный вызов, который не видно четко

siluveru kiran kumar 28.08.2019 07:26

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

Maiya 18.11.2019 17:43

Я предлагаю прочитать overreacted.io/a-complete-guide-to-useeffect Думать о хуках в жизненных циклах на самом деле не так уж и приятно.

moto 22.11.2019 02:13

Это приятно. Но я считаю, что ваш второй и третий useEffect должны читаться как «обновление», а не «обновление».

Jordy 07.05.2020 07:17

Очень классный ответ. Не знал об этом.

ezik 29.12.2020 16:55

Это то, что я искал. Спасибо друг

Gajen 03.08.2021 11:25
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, не позволяющее приложению устанавливать состояние после размонтирования компонента.

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.

useEffect изолированы в своей собственной области видимости и соответственно отображаются. Изображение из https://reactjs.org/docs/hooks-custom.html

Ссылка на решение приветствуется, но убедитесь, что ваш ответ полезен и без нее: добавить контекст вокруг ссылки, чтобы ваши коллеги-пользователи имели некоторое представление о том, что это такое и почему оно существует, а затем процитируйте наиболее важную часть страницы, на которую вы ссылаетесь, в если целевая страница недоступна. Ответы, которые представляют собой чуть больше ссылки, могут быть удалены.

rizerphe 10.05.2020 07:22

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

//componentDidMount
useEffect( () => {

    window.addEventListener("load",  pageLoad);

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

 });

теперь, когда эта часть выполнена, я просто запускаю все, что хочу, из функции pageLoad, как это.

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

Чтобы добавить к принятому ответу, у меня была аналогичная проблема, и я решил ее, используя аналогичный подход с надуманным примером ниже. В этом случае мне нужно было зарегистрировать некоторые параметры componentWillUnmount, и, как описано в исходном вопросе, я не хотел, чтобы он регистрировался каждый раз, когда параметры изменялись.

const componentWillUnmount = useRef(false)

// This is componentWillUnmount
useEffect(() => {
    return () => {
        componentWillUnmount.current = true
    }
}, [])

useEffect(() => {
    return () => {
        // This line only evaluates to true after the componentWillUnmount happens 
        if (componentWillUnmount.current) {
            console.info(params)
        }
    }

}, [params]) // This dependency guarantees that when the componentWillUnmount fires it will log the latest params

Порядок использования эффектов имеет значение, если кому-то еще было интересно

sirclesam 21.12.2021 19:10

Используя пользовательские события js, вы можете эмулировать размонтирование компонентаWillUnmount даже при наличии зависимости.

Проблема:

    useEffect(() => {
    //Dependent Code
    return () => {
        // Desired to perform action on unmount only 'componentWillUnmount' 
        // But it does not
        if (somethingChanged){
            // Perform an Action only if something changed
        }
    }
},[somethingChanged]);

Решение:

// Rewrite this code  to arrange emulate this behaviour

// Decoupling using events
useEffect( () => {
    return () => {
        // Executed only when component unmounts,
        let e = new Event("componentUnmount");
        document.dispatchEvent(e);
    }
}, []);

useEffect( () => {
    function doOnUnmount(){
        if (somethingChanged){
            // Perform an Action only if something changed
        }
    }

    document.addEventListener("componentUnmount",doOnUnmount);
    return () => {
        // This is done whenever value of somethingChanged changes
        document.removeEventListener("componentUnmount",doOnUnmount);
    }

}, [somethingChanged])

Предостережения:использованиеЭффекты должны быть в порядке, использованиеЭффект без зависимости должны быть записаны раньше, чтобы избежать вызова события после его удаления.

Наиболее важной частью этого ответа является предостережение о том, что вы должны использовать хуки useEffect, чтобы

brycejl 15.07.2021 17:40

Другие вопросы по теме