Я получаю это предупреждение, когда использую свой метод публикации выборки, как я могу отменить все подписки и асинхронные задачи в функции очистки 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;
Я вижу, но как это исправить
вы показываете только функции для вызова API, а не то, как или когда вы их вызываете
если вы прокрутите код вниз в функции handleSubmit



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы можете использовать 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 подходит для решения этой проблемы, так как это сильно отличается от изменения состояния вашего компонента, это похоже на переменные экземпляра в компонентах класса, изменение которых не вызовет повторную визуализацию.
и в обновлении состояния поставить обе мои функции?
@KubaKluzniak Вы имеете в виду вызывать функции, которые отправляют/извлекают некоторые данные и обновляют состояние? Да.
у меня не работает форма, когда я помещаю эти функции, они выполняют их после ввода данных
Это зависит от того, как вы используете логическое значение, вы можете, например, иметь useEffect в своем компоненте, но использовать логическое значение внутри другой функции, которая находится вне useEffect, но находится внутри компонента.
Этот useEffect будет срабатывать при каждом рендеринге, потому что у него нет массива зависимостей. Я не думаю, что ты этого хочешь. Я думаю, вы забыли включить пустой массив зависимостей.
@jonS90 jonS90, я хочу показать, что мы можем использовать useRef ловушку, чтобы избежать обновления состояния, когда компонент размонтирован. Использование useEffect зависит от OP.
Я согласен с Рамешем в использовании исх. Я решил показать, как его можно извлечь в пользовательский хук.
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;
Ваш пользовательский хук ничего не возвращает. Я отредактирую это.
Может быть, это глупый вопрос, но что мне нужно вставить, если (hasUnmountedRef) { return; }
@KubaKluzniak это просто оговорка о защите. Это мешает вам выполнить остальную часть функции. Он должен иметь «возврат» и ничего больше.
(Сделаны некоторые дополнительные исправления для использования ref или значения ref в правильных местах)
Знаете ли вы, почему пользовательский хук не может напрямую возвращать hasUnmountedRed.current? Это потому, что когда мы используем пользовательский хук, сохраняемое значение не является динамическим из-за константы, и только .current может измениться?
это предупреждение... не ошибка