在未安装的组件上反应状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏

时间:2021-02-11 04:55:32

标签: reactjs callback react-hooks amazon-cognito use-effect

我正在练习 AWS 的 Cognito。对于前端,我使用 React,而对于路由,我使用 React-router-dom。对于 Cognito 验证,我使用 amazon-cognito-identity-js 包。我的 Congito signinsignupconfirmation 逻辑工作正常。我做了一个辅助函数来验证 Congnito。并在不同的组件中重用它。我将导航栏分成两个部分。从Congnito当前用户我制作了一个回调函数并在useEffect中使用它,并且依赖项放置了回调函数,默认情况下getAuthenticatedUser为null。我添加了获取数据的条件,如果 getAuthenticatedUser 然后重定向到 signinsignup 页面。由于这种情况,我收到错误:Can't perform a React state update on an unmounted component.....。此外,当我登录时,它不会更改导航栏名称,我必须刷新浏览器才能看到更改。我在 codesandbox 中分享了我的代码。

这是我的辅助函数

    import React, { useState, useCallback, useEffect, useMemo } from 'react';
import { CognitoUserPool } from 'amazon-cognito-identity-js';

const Pool_Data = {
  UserPoolId: 'us-east-1_IEyFfUupx',
  ClientId: '63fc9g5c3g9vhqdalrv9eqhoa2',
};

export default function useHandler() {
  const [state, setstate] = useState({
    loading: false,
    isAuthenticated: false
  })

  const { loading, isAuthenticated } = state;

  const userPool = new CognitoUserPool(Pool_Data)

  const getAuthenticatedUser = useCallback(() => {
    return userPool.getCurrentUser();
  },
    [],
  );

  console.log(getAuthenticatedUser());


  useEffect(() => {
    getAuthenticatedUser()
  }, [getAuthenticatedUser])

  const signOut = () => {
    return userPool.getCurrentUser()?.signOut()
  }
  console.log(getAuthenticatedUser());

  return {
    loading,
    isAuthenticated,
    userPool,
    getAuthenticatedUser,
    signOut
  }
};

这是我的导航

import React, { useEffect } from "react";
import { Link } from "react-router-dom";
import SigninLinks from './SigninLinks';
import SignoutLinks from './SignoutLinks';
import useHandlder from '../configHandler/useHandler';


const Nav = () => {
  const { getAuthenticatedUser } = useHandlder();


  const Links = getAuthenticatedUser() ? <SigninLinks /> : <SignoutLinks />
  return (
    <nav className="nav-wrapper grey darken-3">
      <div className="container">
        <h2 className="brand-logo">Logo</h2>
        {
          Links
        }

      </div>
    </nav>
  );
};

export default Nav;

这是显示数据和获取错误信息的主屏幕

import React, { useState, useEffect } from "react";
import { api } from './api';
import useHandlder from './configHandler/useHandler'
import { Redirect } from 'react-router-dom';

const Home = () => {
  const [state, setstate] = useState([]);
  const { getAuthenticatedUser } = useHandlder();

  useEffect(() => {
    fetchData()
  }, [])

  const fetchData = async () => {
    const response = await fetch(`https://jsonplaceholder.typicode.com/posts`);
    const data = await response.json();
    setstate(data)
  }

  return getAuthenticatedUser() === null ? <Redirect to="/signin" /> : //In here is the //error happening.
    <div className="row">
      <h1>hello welcome to home</h1>
      {
        state?.map((i: string, id: number) => <h1 key={id}>{i.title}</h1>)
      }
    </div>

};

export default Home;

1 个答案:

答案 0 :(得分:1)

问题

问题是您的应用在主 ("/") 路径上启动并呈现 Home 组件。 Home 在挂载时发起 GET 请求并检查经过身份验证的用户,如果没有,则重定向到您的“/signin”路由。

fetch异步,因此当发生重定向时,GET 请求正在解析 Home 已卸载并尝试更新具有响应数据的本地状态,但不能。

解决方案

您需要使用 Abort Controller 取消进行中的请求。如果组件卸载,效果清除功能会取消获取请求。在 Home 中更新 useEffect 钩子以创建要在清理函数中使用的 AbortControllersignal

useEffect(() => {
  const controller = new AbortController(); // <-- create controller
  const { signal } = controller; // <-- get signal for request

  const fetchData = async () => {
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/posts`,
      { signal } // <-- pass signal with options
    );
    const data = await response.json();
    setstate(data);
  };

  fetchData();

  return () => controller.abort(); // <-- return cleanup function to abort
}, []);

演示

Edit Cognito (forked)