首页 > 解决方案 > 清理 useEffect 的正确方法

问题描述

我有useEffect回调,这给了我一个错误:

警告:无法对未安装的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要解决此问题,请在 useEffect 清理函数中取消所有订阅和异步任务。

这是我的代码:

import React, {useEffect, useState} from 'react'
import { useTranslation } from 'react-i18next'
import firebase from 'firebase/app'
import '../firebase'
import Input from '../Components/Input'
import Button from '../Components/Button'
import { useHistory, useParams } from 'react-router-dom'
import { connect } from 'react-redux'
import { isAuth } from '../redux/actions/session/isAuth'
import Header from '../Modules/Header'
import Loader from '../Components/Loader'
import logo from '../media/logo/seanor_logo.svg'

let db = firebase.firestore()

const Login = ({setIsAuth, agencyData, userData, userUID, isAuth}) => {
    const { t } = useTranslation()
    let history = useHistory()
    let { agency } = useParams()

    // Change document title
    document.title = `${t('login')}`

    const [loading, setLoading] = useState(false)
    // Input states
    const [email, setEmail] = useState('')
    const [password, setPassword] = useState('')
    const [error, setError] = useState(false)
    const [agencyErr, setAgencyErr] = useState(false)

    useEffect( () => {
        const checkUserType = () => {
            // Check is user logged in and redirects to dashboard
            if (userData !== null && isAuth) {
                if (userData.type === 'employee') {
                    history.push(`/${agency}/dashboard/${userUID}`)
                } else if (userData.type === 'crewagency') {
                    history.push(`/${agency}/crew-dashboard/`)
                } else if ( userData.type === 'keyagency') {
                    history.push(`/${agency}/key-dashboard/`)
                }
            }
        }
        return () => checkUserType()
    }, [agency, history, userData, userUID, isAuth])

    const submit = () => {
        setAgencyErr(false)
        setLoading(true)

        firebase.auth()
        .signInWithEmailAndPassword(email, password)
        .then(res => {
            let resData = JSON.stringify(res.user)
            resData = JSON.parse(resData)
            let uid = resData.uid
            // Check is usere belongs to agency
            db.collection('users').doc(uid).get()
            .then( res => {
                let resData = JSON.stringify(res.data())
                resData = JSON.parse(resData)
                if (resData.data.agencyId === agency) {
                    // Check user type and redirect to dashboar by type
                    if (resData.data.type === 'employee') {
                        history.push(`/${agency}/dashboard/${uid}`)
                    } else if (resData.data.type === 'crewagency') {
                        history.push(`/${agency}/crew-dashboard`)
                    } else if ( resData.data.type === 'keyagency') {
                        history.push(`/${agency}/key-dashboard`)
                    }
                } else {
                    firebase.auth().signOut()
                    setAgencyErr(true)
                }
                setLoading(false)
            })
            .catch(err => console.log('User info error', err))
            setIsAuth(true)
        })
        .catch(err => {
            console.log('Login error: ', err.message)
            setError(true)
            setLoading(false)
        })
    }

    return ( 
        <div>
            {loading && <Loader />}
            <Header />
            <div className='login'>
                <div className='login__box'>
                    <div className='login__logo'>
                        <img src={logo} alt='logo' />
                    </div>
                    <div className='login__box-title'>
                        <h2>{t('loginToCrewManager')}</h2>
                    </div>
                    <div className='login__input'>
                        <div className='login__input-label'>
                            {t('email')}
                        </div>
                        <Input 
                            type='email'
                            handleInput={(value) => setEmail(value)}
                        />
                    </div>
                    <div className='login__input'>
                        <div className='login__input-label'>
                            {t('password')}
                        </div>
                        <Input 
                            type='password'
                            handleInput={(value) => setPassword(value)}
                        />
                    </div>
                    {error &&
                        <div className='error'>
                            {t('loginError')}
                        </div>}
                    {agencyErr &&
                        <div className='error'>
                            {t('agencyErrorLogin')}
                        </div>}
                    <div className='login__submit'>
                        <Button 
                            text='login'
                            handleClick={() => submit()}
                        />
                    </div>
                    <div className='login__registration'>
                        <a href={`/${agency}/reset-password`}>{t('resetPasswordLogin')}</a>
                    </div>
                    <div className='login__registration'>
                        <a href={`/${agency}/registration`}>{t('newUserRegistration')}</a>
                    </div>
                </div>
            </div>
        </div>
    )

}

const mapStateToProps = state => {
    return {
        agencyData: state.agencyDataRed.obj,
        isAuth: state.isAuthRed.bool
    }
}

const mapDispatchToProps = dispatch => {
    return {
        setIsAuth: bool => dispatch(isAuth(bool))
    }
}
 
export default connect(mapStateToProps, mapDispatchToProps)(Login)

也许我不明白清理功能?我的错误在哪里?

标签: reactjsreact-hooksuse-effect

解决方案


我认为问题出在您的submit函数中,并且您states在更改 url 后设置了一个。我移动setLoading(false)了一点,试试这个:

const submit = () => {
  setAgencyErr(false);
  setLoading(true);

  firebase
    .auth()
    .signInWithEmailAndPassword(email, password)
    .then((res) => {
      let resData = JSON.stringify(res.user);
      resData = JSON.parse(resData);
      let uid = resData.uid;
      // Check is usere belongs to agency
      db.collection("users")
        .doc(uid)
        .get()
        .then((res) => {
          let resData = JSON.stringify(res.data());
          resData = JSON.parse(resData);
          if (resData.data.agencyId === agency) {
            // Check user type and redirect to dashboar by type
            if (resData.data.type === "employee") {
              history.push(`/${agency}/dashboard/${uid}`);
            } else if (resData.data.type === "crewagency") {
              history.push(`/${agency}/crew-dashboard`);
            } else if (resData.data.type === "keyagency") {
              history.push(`/${agency}/key-dashboard`);
            }
          } else {
            firebase.auth().signOut();
            setAgencyErr(true);
            setLoading(false); //<=== HERE
          }
        })
        .catch((err) => console.log("User info error", err));
      setIsAuth(true);
    })
    .catch((err) => {
      console.log("Login error: ", err.message);
      setError(true);
      setLoading(false);
    });
};

setIsAuth(true)是需要搬到正确位置的候选人之一


推荐阅读