Невозможно выполнить обновление состояния React для несмонтированного компонента с помощью метода POST

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

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

import React from "react";
import { useHistory } from "react-router-dom";
import { UPLOAD_PRESET, CLOUD_NAME, SERVER_API } from "../../config";

const uploadImage = async (file) => {
  const url = `https://api.cloudinary.com/v1_1/${CLOUD_NAME}/upload`;
  const formData = new FormData();
  formData.append("file", file);
  formData.append("upload_preset", UPLOAD_PRESET);

  const res = await fetch(url, {
    method: "POST",
    body: formData,
  });

  if (!res.ok) {
    throw new Error(`Can't upload image. ${res.status}`);
  }

  const data = await res.json();
  return await data.eager[0].secure_url;
};

const createAlbum = async (data) => {
  const res = await fetch(`${SERVER_API}/api/v1/albums`, {
    method: "POST",
    body: JSON.stringify(data),
    headers: {
      "Content-Type": "application/json",
    },
  });

  if (!res.ok) {
    throw new Error(`An error has occurred: ${res.status}`);
  }

  const json = await res.json();
  return json.data._id;
};

const Form = ({ file, loading, setError, album, color, children }) => {
  let history = useHistory();

  const clearError = () => setError("");

  const handleSubmit = async (e) => {
    e.preventDefault();
    clearError();
    try {
      if (!file) {
        throw new Error("Please select a file to add.");
      }

      if (!album.trim("") || !color.trim()) {
        throw new Error("Please enter all the field values.");
      }

      loading(true);

      const fileUrl = await uploadImage(file);

      const data = {
        name: album,
        bckImgUrl: fileUrl,
        color: color,
      };

      const albumId = await createAlbum(data);

      history.push(`/albums/${albumId}`);
    } catch (error) {
      setError(error.message);
    } finally {
      loading(false);
    }
  };
  return <form onSubmit = {handleSubmit}>{children}</form>;
};

export default Form;

это предупреждение... не ошибка

assembler 24.12.2020 14:29

Я вижу, но как это исправить

Kuba Kluzniak 24.12.2020 14:32

вы показываете только функции для вызова API, а не то, как или когда вы их вызываете

assembler 24.12.2020 14:34

если вы прокрутите код вниз в функции handleSubmit

Kuba Kluzniak 24.12.2020 14:35
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
4
453
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете использовать React.useRef для этого:

В вашем компоненте:

const hasUnmounted = React.useRef(false);

React.useEffect(() => {

 // maybe you have your side effects here, so you can use the boolean to avoid 
 // state updates when the component is unmounted

 if (!hasUnmounted.current) {
  // do state update 
 }
 return () => {
  hasUnmounted.current = true;
 }
}, [])

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

и в обновлении состояния поставить обе мои функции?

Kuba Kluzniak 24.12.2020 14:46

@KubaKluzniak Вы имеете в виду вызывать функции, которые отправляют/извлекают некоторые данные и обновляют состояние? Да.

Ramesh Reddy 24.12.2020 14:53

у меня не работает форма, когда я помещаю эти функции, они выполняют их после ввода данных

Kuba Kluzniak 24.12.2020 15:14

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

Ramesh Reddy 24.12.2020 15:30

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

jonS90 24.12.2020 19:50

@jonS90 jonS90, я хочу показать, что мы можем использовать useRef ловушку, чтобы избежать обновления состояния, когда компонент размонтирован. Использование useEffect зависит от OP.

Ramesh Reddy 24.12.2020 20:35
Ответ принят как подходящий

Я согласен с Рамешем в использовании исх. Я решил показать, как его можно извлечь в пользовательский хук.

function useHasUnmountedRef() {
  const hasUnmountedRef = useRef(false);
  useEffect(() => {
    return () => {
      hasUnmountedRef.current = true;
    }
  }, []);
  return hasUnmountedRef;
}

function Form() {

  const hasUnmountedRef = useHasUnmountedRef();

  const handleSubmit = async () => {

    await asyncStuff();

    if (hasUnmountedRef.current) {
      // escape early because component has unmounted
      return;
    }

    // Thanks to the guard clause above, you can guarantee at this
    // point that your component is still mounted. You can perform
    // state updates without generating a React warning. 
    //
    // If you do another "await" however, you will need to check
    // again. Everytime you await something async, there is a chance
    // that the component could have unmounted while waiting for the
    // async stuff to complete.

  };

  return (
    <form onSubmit = {handleSubmit} />
  );
}

export default Form;

Ваш пользовательский хук ничего не возвращает. Я отредактирую это.

Ramesh Reddy 24.12.2020 20:37

Может быть, это глупый вопрос, но что мне нужно вставить, если (hasUnmountedRef) { return; }

Kuba Kluzniak 25.12.2020 00:34

@KubaKluzniak это просто оговорка о защите. Это мешает вам выполнить остальную часть функции. Он должен иметь «возврат» и ничего больше.

jonS90 25.12.2020 04:48

(Сделаны некоторые дополнительные исправления для использования ref или значения ref в правильных местах)

jonS90 25.12.2020 04:53

Знаете ли вы, почему пользовательский хук не может напрямую возвращать hasUnmountedRed.current? Это потому, что когда мы используем пользовательский хук, сохраняемое значение не является динамическим из-за константы, и только .current может измениться?

Sean A.S. Mengis 01.04.2022 12:58

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