组件将在卸载后保留状态

问题描述 投票:2回答:2

组件即使在卸载后也会保留状态

我正在与Formik建立一个反馈表,并希望从类组件转移到钩子,但面对提到的困难。

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"或根据服务器响应可能显示错误消息的表单,我有条件地呈现成功消息。我的类组件可以正常使用此代码:

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组件,但那是我的错误呢?

reactjs react-hooks
2个回答
2
投票

发生上述行为是因为效果也在初始渲染上运行,在这种情况下,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]);
}

1
投票

你可以使用<Feedback key={someKey} />

这将确保在您重新打开它时创建一个新的Feedback组件实例,从而将从状态中删除旧的成功/失败消息。

© www.soinside.com 2019 - 2024. All rights reserved.