我有这个地方的更新表格,我从后端获取其数据以在useEffect中添加初始输入,但出现此错误
无法在已卸载的组件上执行React状态更新。这是空操作,但它表明应用程序中发生内存泄漏。要修复,请取消使用useEffect清理功能中的所有订阅和异步任务。
我知道问题与更新状态之前卸载组件有关,但是我尝试了许多解决方案,但没有用。任何人都有一个解决办法
const UpdatePlace = () => {
const placeId = useParams().pId;
const [loadedPlace, setLoadedPlace] = useState();
// const [isLoading, setIsLoading] = useState(true);
const { error, sendRequest, clearError } = useHttpClient();
const [isLoading, formState, inputHandler, setFormData] = useForm(
{
title: {
value: "",
isValid: false,
},
description: {
value: "",
isValid: false,
},
},
true
);
useEffect(() => {
const fetchPlace = async () => {
try {
const res = await sendRequest(`/api/places/${placeId}`);
await setLoadedPlace(res.data.place);
setFormData(
{
title: {
value: res.data.place.title,
isValid: true,
},
description: {
value: res.data.place.description,
isValid: true,
},
},
true
);
} catch (err) {}
};
fetchPlace();
}, [sendRequest, placeId, setFormData]);
if (!loadedPlace && !error) {
return (
<div className="center" style={{ maxWidth: "400px", margin: "0 auto" }}>
<Card>
<h2>No place found!</h2>
</Card>
</div>
);
}
const placeUpdateSubmitHandler = (e) => {
e.preventDefault();
console.log(formState.inputs, formState.isFormValid);
};
return (
<>
{isLoading ? (
<LoadingSpinner asOverlay />
) : error ? (
<ErrorModal error={error} onClear={clearError} />
) : (
<>
<Title label="Update place" />
<form className="place-form" onSubmit={placeUpdateSubmitHandler}>
<Input
element="input"
type="text"
id="title"
label="Update title"
validators={[VALIDATOR_REQUIRE()]}
errorText="please enter valid title"
onInput={inputHandler}
initialValue={loadedPlace.title}
initialValid={true}
/>
<Input
element="textarea"
id="description"
label="Update description"
validators={[VALIDATOR_REQUIRE(), VALIDATOR_MINLENGTH(5)]}
errorText="please enter valid description (min 5 chars) "
onInput={inputHandler}
initialValue={loadedPlace.description}
initialValid={true}
/>
<Button type="submit" disabled={!formState.isFormValid}>
Update place
</Button>
</form>
</>
)}
</>
);
};
答案 0 :(得分:0)
您可以将useEffect与带有清除功能的[]一起使用,因为它将像这样执行最后一个:
useEffect(() => {
return () => {
console.log('cleaned up');
}
},[])
答案 1 :(得分:0)
此错误表示从该页面导航离开后,您的请求完成,并且它尝试更新已经卸载的组件。您应该使用AbortController放弃请求。这样的事情应该起作用:
public ByteArrayInputStream generatePDF2(String htmlFile, String fontset) throws IOException {
ByteArrayOutputStream pdf=new ByteArrayOutputStream();
HtmlConverter.convertToPdf(htmlFile, pdf);
ByteArrayInputStream inputStream = new ByteArrayInputStream(pdf.toByteArray());
return inputStream;
}
编辑:修复渲染时未定义的obj键/值
以上警告不会阻止您的组件渲染。初始化常量 loadedPlace 的方式将给您带来未定义的错误并阻止呈现组件。您将其初始化为null,但将其用作Input initialValue = {loadedPlace.title}中的对象。当您的组件尝试执行第一个渲染时,它将读取该值的状态,但无法找到键并中断。
尝试解决此问题:
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
const fetchPlace = async () => {
try {
const res = await fetch(`/api/places/${placeId}`, { signal }).then(response => {
return response;
}).catch(e => {
console.warn(`Fetch 1 error: ${e.message}`);
});
await setLoadedPlace(res.data.place);
setFormData(
{
title: {
value: res.data.place.title,
isValid: true,
},
description: {
value: res.data.place.description,
isValid: true,
},
},
true
);
} catch (err) {}
};
fetchPlace();
return () => {
controller.abort();
};
}, [sendRequest, placeId, setFormData]);
始终确保使用对象时,在渲染时不要使用未定义的键。