无法使用 fetch POST 方法对未安装的组件执行 React 状态更新
Posted
技术标签:
【中文标题】无法使用 fetch POST 方法对未安装的组件执行 React 状态更新【英文标题】:Can't perform a React state update on an unmounted component with fetch POST method 【发布时间】:2021-04-02 22:33:23 【问题描述】:我在使用 fetch post 方法时收到此警告,如何取消 useEffect 清理函数中的所有订阅和异步任务。使用我的 Post 方法。
警告:无法对未安装的组件执行 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函数中向下滚动代码 【参考方案1】:我同意 Ramesh 关于使用 ref 的观点。我想我会展示如何将它提取到自定义钩子中。
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 值)【参考方案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
适合解决这个问题,因为它与更改组件的状态非常不同,这有点像类组件中的实例变量,更改它不会触发重新渲染。
【讨论】:
并在状态更新中放入我的两个功能? @KubaKluzniak 你的意思是调用发送/获取一些数据并更新状态的函数?是的。 它对我不起作用,当我放置此函数时,它会在放入数据后执行它们 这取决于您如何使用布尔值,例如,您可以在组件中使用useEffect
,但在 useEffect
之外但在内部的另一个函数中使用布尔值组件。
这个 useEffect 将在每次渲染时触发,因为它没有依赖数组。我不认为你想要那个。我想你忘了包含空依赖数组。以上是关于无法使用 fetch POST 方法对未安装的组件执行 React 状态更新的主要内容,如果未能解决你的问题,请参考以下文章
警告:无法对未安装的组件执行 React 状态更新。在功能组件中
“警告:无法对未安装的组件执行 React 状态更新。” [关闭]