![](/img/trans.png)
[英]React Can't perform a React state update on an unmounted component error
[英]Can't perform a react state update on an unmounted component error
我将在简短的序言中说我已经在这工作了几个小时,感觉我已经尝试了所有的方法。 我还从我的组件中遗漏了很多代码,我认为这些代码与问题无关。 当用户尝试编辑史诗对象(db 中的条目)时,他们将看到这个组件 EditEpic。 在这里,用户还可以从数据库中删除对象,这正是我现在要做的。 删除后,用户将被带回上一页。 这就是我遇到问题的地方。 这是代码
interface IEditEpic extends RouteComponentProps<{
id: string;
}> {
}
interface IProps {
updater?: (val:number) => void;
}
export const EditEpic: React.FC<IEditEpic> = ({match}, props:IProps) => {
const [showAlert2, setShowAlert2] = useState(false);
const [showAlert3, setShowAlert3] = useState(false);
const [showAlert4, setShowAlert4] = useState(false);
const [showAlert5, setShowAlert5] = useState(false);
const [showAlert6, setShowAlert6] = useState(false);
const [showAlert7, setShowAlert7] = useState(false);
const [showAlert8, setShowAlert8] = useState(false);
const [showAlert9, setShowAlert9] = useState(false);
const [showAlert10, setShowAlert10] = useState(false);
const [showAlert11, setShowAlert11] = useState(false);
const [showAlert12, setShowAlert12] = useState(false);
const [resultMessage, setResultMessage] = useState();
const [epic, setEpic] = useState<any>();
const [pet, setPet] = useState({petPoints: 0, id: ""});
const history = useHistory();
const [triggerRefresh, setTriggerFresh] = useState(0);
useEffect(() => {
let isSubscribed:boolean = true;
if (isSubscribed) {
(async () => {
const res = await findEpic(match.params.id);
if (res){
console.log("found epic ", res[0]);
setEpic(res[0]);
}
// set pet
var my_pet:any = await getPet();
if (my_pet)
if (my_pet.length > 0) {
setPet({petPoints: my_pet[0].points, id: my_pet[0]._id});
}
})();
}
return () => {isSubscribed = false};
}, [pet.petPoints]);
const removeEpic = () => {
(async () => {
const result = await deleteEpic(epic);
if (result === DELETE_EPIC_RESULT.pass)
{
console.log("Successful delete");
setShowAlert7(true);
console.log("going back in history");
history.goBack();
}
else if (result === DELETE_GOALS_IN_EPIC_RESULT.fail)
setShowAlert11(true);
else if (result === DELETE_EPIC_RESULT.id_error)
setShowAlert12(true);
else
setShowAlert6(true);
})();
};
console.log("MY props updater", props.updater);
return (
<IonPage>
<IonContent>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonBackButton defaultHref="/home" icon="buttonIcon"/>
</IonButtons>
</IonToolbar>
</IonHeader>
<IonList>
<div style={{display: "flex", justifyContent: "center"}}>
<h1 style={{fontWeight: "bold", textDecoration: "underline"}}>Edit Epic</h1>
</div>
<br/>
<IonItem>
<IonInput
value={epic?.epicTitle}
placeholder="Title"
required={true}
debounce={750}
clearInput={true}
minlength={1}
maxlength={50}
// onIonChange={e => setTitle(e.detail.value!)}
onIonChange={e => setEpic({...epic, epicTitle: e.detail.value!})}
>
</IonInput>
</IonItem>
<br/>
<br/>
<br/>
<IonItem>
<IonLabel position="floating">Description</IonLabel>
<IonTextarea
value={epic?.epicDescription}
placeholder="Please enter your description here"
onIonChange={e => setEpic({...epic, epicDescription: e.detail.value!})}>
</IonTextarea>
</IonItem>
<br/>
<br/>
<DateTimePicker dateType={DATE_ENUMS.start} setDate={setEpic} goalState={epic}/>
<br/>
<br/>
<DateTimePicker dateType={DATE_ENUMS.end} setDate={setEpic} goalState={epic}/>
<br/>
<br/>
<IonFab horizontal="end" vertical="top" slot="fixed">
<IonFabButton color="danger" onClick={() => setShowAlert5(true)}>
<IonIcon icon={trashOutline}/>
</IonFabButton>
</IonFab>
<IonAlert
isOpen={showAlert6}
onDidDismiss={() => setShowAlert6(false)}
header={'Error'}
message={DELETE_EPIC_RESULT.error}
buttons={["OK"]}
/>
<IonAlert
isOpen={showAlert7}
onDidDismiss={() => setShowAlert7(false)}
header={'Success'}
message={DELETE_EPIC_RESULT.pass}
buttons={["OK"]}
/>
<IonAlert
isOpen={showAlert11}
onDidDismiss={() => setShowAlert11(false)}
header={'Error'}
message={DELETE_GOALS_IN_EPIC_RESULT.fail}
buttons={["OK"]}
/>
<IonAlert
isOpen={showAlert12}
onDidDismiss={() => {
setShowAlert12(false);
setTriggerFresh(triggerRefresh+ 1);
}}
header={'Error'}
message={DELETE_EPIC_RESULT.id_error}
buttons={["OK"]}
/>
<IonAlert
isOpen={showAlert5}
onDidDismiss={() => {
setShowAlert5(false);
// close modal if the insert was successful
}}
header={'Delete Epic'}
message={"Are you sure that you would like to delete the selected epic? " +
"Goals associated with the epic will be deleted as well."}
buttons={[{
text: "NO",
handler: () => {
// do nothing
}
}, {
text: "YES",
handler: () => {
removeEpic();
}
}]}
/>
</IonList>
</IonContent>
</IonPage>
)
};
export default EditEpic;
这里重要的是我的组件返回的最后一个 IonAlert 标记。 在警报的按钮处理程序中,如果用户单击“是”,我将运行函数 removeEpic()。 这个函数删除了数据库中的史诗对象,我想要发生的是回到历史的最后一页,因为用户刚刚删除了他们正在查看的内容。 当我将 history.goBack() 注释掉时,代码运行良好。
我在想这个问题可能是因为 history.goBack() 在异步函数中被调用,也许是因为该函数仍在进行中,而我正在返回一个页面,react 会给我那个错误。 但是,从 removeEpic() 中注释掉 goBack() 并将其放在 IonAlert 中的 removeEpic() 调用之后也不起作用。 我不知道除此之外还能尝试什么。 我也在 useEffect 中尝试了一些清理东西,但没有任何效果。 任何帮助,将不胜感激。 如果需要,我可以提供更多信息。
另外,我的堆栈跟踪看起来像这样
index.js:1 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in EditEpic (created by Context.Consumer)
in Route (at App.tsx:66)
in View (created by StackManagerInner)
这是我会做的:
EditEpic
组件之上添加const isMounted = useRef(true)
useEffect
,它看起来像这样:useEffect(() => { return () => { isMounted.current = false} }, [])
setSomething..
的代码,并添加检查isMounted.current && setSomething..
想法是,使用useRef
您可以跟踪组件是否已安装,而不是仅在组件已安装时更新状态。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.