为什么这些功能工作不同?

时间:2019-03-28 01:12:53

标签: javascript reactjs

仅在未卸载组件的情况下,我试图在进行API调用后设置属性的状态。在第一个函数中,变量“ unmount”在函数“ Component”中初始化。在这种情况下,我会收到以下警告:“无法在已卸载的组件上执行React状态更新。这是空操作,但表明您的应用程序中存在内存泄漏。”

在第二个函数中,我全局初始化了变量“ unmount”,在这种情况下,我没有收到任何警告。

显示警告:

function Component() {
  const [emailSent, setEmailSent] = useState(false);

  var unmounted = false;
  async function handleClickEvent() {
  try {
   await AuthApi.sendRecoverAccountEmail('123');
   !unmounted && setEmailSent(true);
  } catch (err) {
    !unmounted && setIsSendingEmail(false);
  }
 }

 useEffect(() => {
   return () => {
    unmounted = true;
   };
 }, []);
}

没有警告:

var unmounted = false;
function Component() {
const [emailSent, setEmailSent] = useState(false);

async function handleSendEmail(formValues) {
 try {
  await AuthApi.sendRecoverAccountEmail('123');
  !unmounted && setEmailSent(true);
 } catch (err) {
  !unmounted && setIsSendingEmail(false);
 }
}

useEffect(() => {
  return () => {
   unmounted = true;
  };
 }, []);
}

任何人都可以解释为什么会这样吗?

2 个答案:

答案 0 :(得分:3)

在第一个示例中,unmounted将始终在每次渲染后false

这是不使用全局实例的正确方法:

function Component() {
  const [emailSent, setEmailSent] = useState(false);
  const unmounted = useRef(false);

  async function handleSendEmail(formValues) {
    try {
      await AuthApi.sendRecoverAccountEmail('123');
      !unmounted.current && setEmailSent(true);
    } catch (err) {
      !unmounted.current && setIsSendingEmail(false);
    }
  }

  useEffect(() => {
    return () => {
      unmounted.current = true;
    };
  }, []);
}

答案 1 :(得分:0)

一个有趣的问题。您可能会发现FAQ about hooks很有用,因为我认为它专门针对您的问题。

在第一个示例中,卸载的var是组件属性的一部分,在第二个示例中,它只是作为javascript闭包的一部分而被提取的。

通常,您需要确保将安装的参数作为componentDidUnmount lifecycle method.的一部分

我认为,如果您将unmount添加到依赖项列表中,则可能有效吗?我通常使用Clojurescript中另一个框架的react,所以我并不完全了解主要javascript接口的语义,但这至少是为什么您会收到第一个示例警告的原因。

在第一个示例中,如果将最后一部分更改为以下内容会发生什么?

useEffect(() => {
  return () => {
   unmounted = true;
  };
 }, [unmounted]);
}

您可能需要将unmount定义为更正式的react属性,而不只是组件中包含的属性。