组件将在卸载后保留状态
Component will preserve state after unmounting it
组件即使在卸载后也会保留状态
我正在使用 Formik 构建反馈表,并希望从 class 组件转移到挂钩,但面临上述困难。
function Feedback(props) {
const [fileInfo, setFileInfo] = useState("");
const [feedbackStatus, setFeedbackStatus] = useState("");
let timer = null;
useEffect(() => {
const status = props.feedbackResponse.status;
if (status) {
if (status >= 200 && status < 300) {
setFeedbackStatus("success");
timer = setTimeout(() => {
props.history.goBack();
}, 2500);
} else if (status === "pending") {
setFeedbackStatus("pending");
} else {
setFeedbackStatus("error");
}
}
return () => {
clearInterval(timer);
}
}, [props.feedbackResponse.status]);
// ...code ommited for brevity
}
此效果在我提交表单并等待服务器响应后成功运行。 Feedback
组件是 react-router
模态组件,如果它重要的话。但是,如果我重新打开该模式,我会看到一条成功消息而不是新表单。在我的 return
中,如果 feedbackStatus === "success"
或根据服务器响应可能会显示错误消息的表单,我有条件地呈现一条成功消息。我的 class 组件可以正常使用此代码:
componentDidUpdate(prevProps) {
const status = this.props.feedbackResponse.status;
if (prevProps.feedbackResponse.status !== status) {
if (status >= 200 && status < 300) {
this.setState({feedbackStatus: "success"});
this.timer = setTimeout(() => {
this.props.history.goBack();
}, 2500);
} else if (status === "pending") {
this.setState({feedbackStatus: "pending"});
} else {
this.setState({feedbackStatus: "error"});
};
}
}
componentWillUnmount() {
clearInterval(this.timer);
}
预期输出:在成功提交表单后重新打开此模态组件应该会呈现一个新表单,但它会呈现之前的提交状态。这让我认为我根本没有卸载我的 Feedback
组件,但我的错误在哪里呢?
上述行为的发生是因为初始渲染的效果也是 运行,在这种情况下,props.feedbackStatus
可能会从以前的实例中保留下来。
由于您只希望在组件更新时执行效果,因此您需要在初始渲染时停止执行 useEffect 即使您将值传递给依赖项数组也会发生这种情况.您可以使用 useRef
function Feedback(props) {
const [fileInfo, setFileInfo] = useState("");
const [feedbackStatus, setFeedbackStatus] = useState("");
const isInitialRender = useRef(true);
let timer = null;
useEffect(() => {
if(isInitialRender.current === true) {
isInitialRender.current = false;
} else {
const status = props.feedbackResponse.status;
if (status) {
if (status >= 200 && status < 300) {
setFeedbackStatus("success");
timer = setTimeout(() => {
props.history.goBack();
}, 2500);
} else if (status === "pending") {
setFeedbackStatus("pending");
} else {
setFeedbackStatus("error");
}
}
}
return () => {
clearInterval(timer);
}
}, [props.feedbackResponse.status]);
}
您可以使用 <Feedback key={someKey} />
.
这将确保在您重新打开反馈组件时创建一个新实例,因此您的旧 success/failure 消息将从状态中删除。
组件即使在卸载后也会保留状态
我正在使用 Formik 构建反馈表,并希望从 class 组件转移到挂钩,但面临上述困难。
function Feedback(props) {
const [fileInfo, setFileInfo] = useState("");
const [feedbackStatus, setFeedbackStatus] = useState("");
let timer = null;
useEffect(() => {
const status = props.feedbackResponse.status;
if (status) {
if (status >= 200 && status < 300) {
setFeedbackStatus("success");
timer = setTimeout(() => {
props.history.goBack();
}, 2500);
} else if (status === "pending") {
setFeedbackStatus("pending");
} else {
setFeedbackStatus("error");
}
}
return () => {
clearInterval(timer);
}
}, [props.feedbackResponse.status]);
// ...code ommited for brevity
}
此效果在我提交表单并等待服务器响应后成功运行。 Feedback
组件是 react-router
模态组件,如果它重要的话。但是,如果我重新打开该模式,我会看到一条成功消息而不是新表单。在我的 return
中,如果 feedbackStatus === "success"
或根据服务器响应可能会显示错误消息的表单,我有条件地呈现一条成功消息。我的 class 组件可以正常使用此代码:
componentDidUpdate(prevProps) {
const status = this.props.feedbackResponse.status;
if (prevProps.feedbackResponse.status !== status) {
if (status >= 200 && status < 300) {
this.setState({feedbackStatus: "success"});
this.timer = setTimeout(() => {
this.props.history.goBack();
}, 2500);
} else if (status === "pending") {
this.setState({feedbackStatus: "pending"});
} else {
this.setState({feedbackStatus: "error"});
};
}
}
componentWillUnmount() {
clearInterval(this.timer);
}
预期输出:在成功提交表单后重新打开此模态组件应该会呈现一个新表单,但它会呈现之前的提交状态。这让我认为我根本没有卸载我的 Feedback
组件,但我的错误在哪里呢?
上述行为的发生是因为初始渲染的效果也是 运行,在这种情况下,props.feedbackStatus
可能会从以前的实例中保留下来。
由于您只希望在组件更新时执行效果,因此您需要在初始渲染时停止执行 useEffect 即使您将值传递给依赖项数组也会发生这种情况.您可以使用 useRef
function Feedback(props) {
const [fileInfo, setFileInfo] = useState("");
const [feedbackStatus, setFeedbackStatus] = useState("");
const isInitialRender = useRef(true);
let timer = null;
useEffect(() => {
if(isInitialRender.current === true) {
isInitialRender.current = false;
} else {
const status = props.feedbackResponse.status;
if (status) {
if (status >= 200 && status < 300) {
setFeedbackStatus("success");
timer = setTimeout(() => {
props.history.goBack();
}, 2500);
} else if (status === "pending") {
setFeedbackStatus("pending");
} else {
setFeedbackStatus("error");
}
}
}
return () => {
clearInterval(timer);
}
}, [props.feedbackResponse.status]);
}
您可以使用 <Feedback key={someKey} />
.
这将确保在您重新打开反馈组件时创建一个新实例,因此您的旧 success/failure 消息将从状态中删除。