我目前有一个组件在几秒钟后执行history.push('/')
。但是我收到警告
index.js:1375 Warning: Cannot update during an existing state transition (such as within
渲染). Render methods should be a pure function of props and state.
还有
index.js:1375 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.
我是 React 的新手,我需要做一些清理吗?
这是我的组件。
import React, {useState} from 'react'
import {UsePostOrPutFetch} from "../hooks/postHook";
import "./styles/ConfirmationChange.scss";
import moment from 'moment';
export default function ConfirmatonChange(props) {
const [shouldFetch, setShouldFetch] = useState(false);
const [data,loading,isError, errorMessage] = UsePostOrPutFetch("/send-email/", props.data.location.state.value,"POST", shouldFetch, setShouldFetch);
const [countDown, setCountDown] = useState(5)
let spinner = (
<strong className="c-spinner" role="progressbar">
Loading…
</strong>
);
const changeView = () =>
{
if (countDown < 0) {
props.data.history.push('/')
} else {
setTimeout(() => {
setCountDown(countDown - 1)
}
, 1000)
}
}
return (
<div>
<div className="o-container">
<article className="c-tile">
<div className="c-tile__content">
<div className="c-tile__body u-padding-all">
<button className = "c-btn c-btn--primary u-margin-right" onClick={props.data.history.goBack}>Edit</button>
<button className = "c-btn c-btn--secondary u-margin-right" disabled={loading} onClick={(e) => { setShouldFetch(true)}}>Send</button>
{!loading && data === 200 && !isError ? (
<div className="ConfirmationChange-success-send">
<hr hidden={!data === 200} className="c-divider" />
Email Sent succesfully
<p>You will be redirected shortly....{countDown}</p>
{changeView()}
</div>
) : (loading && !isError ? spinner :
<div className="ConfirmationChange-error-send">
<hr hidden={!isError} className="c-divider" />
{errorMessage}
</div>
)}
</div>
</div>
</article>
</div>
</div>
)
}
这是我的数据获取组件的样子
import { useState, useEffect } from "react";
import { adalApiFetch } from "../config/adal-config";
const UsePostOrPutFetch = (url, sendData, methodType, shouldFetch, setShouldSend) => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [isError, setIsError] = useState(false);
const [errorMessage, setError] = useState("");
useEffect(() => {
const ac = new AbortController();
if (shouldFetch) {
const postOrPutData = async () => {
try {
const response = await adalApiFetch(fetch, url,
{
signal: ac.signal,
method: methodType,
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(sendData)
});
const json = await response.json();
setData(await json);
setLoading(true);
} catch (err) {
setIsError(true);
setError(err.message);
} finally {
setShouldSend(false)
setLoading(false);
}
};
postOrPutData();
}
return () => { ac.abort(); };
}, [shouldFetch, sendData, url, methodType, setShouldSend]);
return [data, loading, isError, errorMessage];
};
export {UsePostOrPutFetch}
任何帮助将不胜感激。
检查 React 钩子 - 检查组件是否已挂载
此警告的最常见原因是当用户启动异步请求,但在完成之前离开页面。
你需要一个componentIsMounted
变量并使用效果和useRef hooks:
const componentIsMounted = useRef(true);
useEffect(() => {
return () => {
componentIsMounted.current = false;
};
}, []);
const changeView = () => {
if (countDown < 0) {
props.data.history.push("/");
} else {
setTimeout(() => {
if (componentIsMounted.current) { // only update the state if the component is mounted
setCountDown(countDown - 1);
}
}, 1000);
}
};
你应该对data fetch component
做同样
是的,您有一个超时,可能会在组件卸载后触发。
您需要添加一个 useEffect,用于清除卸载计时器,如下所示
const timerRef = useRef();
useEffect(() => () => clearTimeout(timerRef.current), [])
const changeView = () => {
if (countDown < 0) {
props.data.history.push("/");
} else {
timerRef.current = setTimeout(() => {
setCountDown(countDown - 1);
}, 1000);
}
};