偶尔会出现在 useEffect() 中创建清理函数的警告

Warning to make a cleanup function in useEffect() occurs occasionally

我正在使用 AWS-Amplify,当用户注销时我收到警告:

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.

它提到它出现在 Profile.tsx 文件中,这是 useEffect() 挂钩。

但问题是错误有时

我一直在测试它,它来来去去,我不知道为什么会这样。

 function Profile() {

  const [user, setUser] = useState<IIntialState | null>(null);

  useEffect(() => {
    checkUser();
    Hub.listen("auth", data => {
      const { payload } = data;
      if (payload.event === "signOut") {
        setUser(null);
      }
    });
  }, []);

  async function checkUser() {
    try {
      const data = await Auth.currentUserPoolUser();
      const userInfo = { username: data.username, ...data.attributes };
      console.log(userInfo);
      setUser(userInfo);
    } catch (err) {
      console.log("error: ", err);
    }
  }
  function signOut() {
    Auth.signOut().catch(err => console.log("error signing out: ", err));
  }
  if (user) {
    return (
      <Container>
        <h1>Profile</h1>
        <h2>Username: {user.username}</h2>
        <h3>Email: {user.email}</h3>
        <h4>Phone: {user.phone_number}</h4>
        <Button onClick={signOut}>Sign Out</Button>
      </Container>
    );
  }
  return <Form setUser={setUser} />;
}

我碰巧是因为你的组件卸载了,但你仍然有订阅。

React useEffect提供卸载功能:

  useEffect(() => {
    Hub.listen("auth", func);
    return () => {
    // unsubscribe here
     Hub.remove("auth", signOut)
    };
 });

而你的 Hub Class 有删除方法

remove(channel: string | RegExp, listener: HubCallback): void

useEffect return 函数中删除您的订阅

Hub.remove()

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.

消息很简单。我们正在尝试更改组件的状态,即使它已被卸载且不可用。

发生这种情况的原因有多种,但最常见的是我们没有取消订阅 websocket 组件,或者这是在异步操作完成之前卸载的。要解决这个问题,您可以这样做:

 useEffect(() => {
    checkUser();
    //check howto remove this listner in aws documentation  
    const listner= Hub.listen("auth", data => {
      const { payload } = data;
      if (payload.event === "signOut") {
        setUser(null);
      }
    });

    //this return function is called on component unmount 
    return ()=>{/* romve the listner here */}
  }, []);

或者采用这种简单的方法。

 useEffect(() => {
    let mounted =true
    Hub.listen("auth", data => {
      const { payload } = data;
      if (payload.event === "signOut" && mounted ) {
        setUser(null);
      }
    });


     //this return function is called on component unmount 
    return ()=>{mounted =false }
  }, []);

Read more about this here.