Почему только первый раз реагирует функциональный компонент, получающий реквизит

#javascript #reactjs #react-hooks #frontend

Вопрос:

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

Я создал компонент, который включает дочерний компонент на основе щелчка. И у дочернего компонента есть кнопка, которая обновляет состояние после некоторого settimeout, которая выдает предупреждение о реакции

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

Что совершенно справедливо. Но чтобы преодолеть это, я передаю enable props от родительского компонента, основываясь на том, что в дочернем компоненте есть условие непосредственно перед настройкой. Так почему же он выдает ошибку только с первого раза?

Чтобы воспроизвести

Нажмите на кнопку дочернего компонента, которая является false , и нажмите кнопку родительского компонента enable , которая размонтирует дочерний компонент.

**Мой вопрос в том, зачем реагировать на ошибку только в первый раз ? И почему это хорошо работает во второй раз **

Родительский компонент

 import { useState } from "react";
import "./styles.css";
import { Test } from "./Test";

export default function App() {
  const [state, setstate] = useState(true);

  const changeState = () => {
    setstate(!state);
  };
  return (
    <div className="App">
      <button onClick={changeState}>enable </button>
      {state amp;amp; <Test enable={state} />}
    </div>
  );
}

 

Дочерний компонент

 import React, { useState } from "react";

export const Test = (props) => {
  const [state, setstate] = useState(false);

  const fetchData = () => {
    setstate(!state);
    if (props.enable) {
      setTimeout(() => {
        setstate(false);
      }, 1000);
    }
  };

  return (
    <>
      <button onClick={fetchData}> {`${state}`}</button>
    </>
  );
};

 

Ссылка на Codesandbox для тестирования

Комментарии:

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

Ответ №1:

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

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

 import React, { useState, useEffect } from "react";

export const Test = (props) => {
  const [state, setstate] = useState(false);

  useEffect(() => {
    if (props.enable) {
      const timer = setTimeout(() => {
        setstate(false);
      }, 1000);

      return () => clearTimeout(timer);
    }
  }, [state, props.enable]);

  const fetchData = () => {
    setstate((prev) => !prev);
  };

  return (
    <>
      <button onClick={fetchData}> {`${state}`}</button>
    </>
  );
};
 

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

Примечания:

  1. В вашем случае мы можем удалить функцию и использовать setState непосредственно на вашей кнопке.
  2. Предпочитаете использовать обратный вызов в своей функции, например const fetchData = useCAllback...
  3. Вы можете использовать setstate((prev) => !prev); его в качестве моментального снимка, и он полезен, когда вы зависите от старого значения..но, возможно, в некоторых случаях он тоже не нужен, но просто для того, чтобы знать об этой функции.

Обновление 1:

Что такое Подписка:

Вы можете сказать, что подписка представляет собой доступный ресурс, такой как выполнение наблюдаемого. У подписки есть один важный метод, отмена подписки, который не принимает аргументов и просто распоряжается ресурсом, принадлежащим подписке, другими словами, вы можете сказать «да», любая асинхронная задача или любое задание будет вызвано для реагирования на состояние жизненного цикла и его необходимое для наблюдения за изменениями, затем вы говорите о подписке, например, API или тайм-аут или интервал времени и так далее, любое из этих действий, которые необходимо очистить до подписки (остановить наблюдателя — отменить подписку), чтобы предотвратить утечку памяти и очистить память, чтобы сохранить поток состояний в безопасности и предотвратить ненужный повторный запуск.

Комментарии:

1. Происходит ли это из-за отключения времени !! И не могли бы вы, пожалуйста, объяснить, что такое подписка ? Насколько мне известно, вызывающий API, любая асинхронная задача, такая как обещание, является подпиской !!

2. Хороший вопрос, вы можете сказать, что подписка представляет собой одноразовый ресурс, такой как выполнение наблюдаемого. У подписки есть один важный метод, отмена подписки, который не принимает аргументов и просто распоряжается ресурсом, принадлежащим подписке, другими словами, вы можете сказать «да», любая асинхронная задача или любое задание будет вызвано для реагирования на состояние жизненного цикла и его необходимое для наблюдения за изменениями, затем вы говорите о подписке, например, api или тайм-аут или интервал и т. Д., Это необходимо для очистки предварительной подписки (остановить наблюдателя — отменить подписку), чтобы предотвратить утечку памяти и очистить память и сохранить поток состояний в безопасности

3. Основываясь на предыдущем комментарии, мы можем ответить «Происходит ли это из-за setTimeout «, да

4. Начальная настройка времени рендеринга остается в памяти, что является единственной причиной всего этого. Во второй раз в моем коде, если из-за этого условие прекращает выполнение, я не вижу ошибки. Я прав?

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