React / Memory Leak useEffect with ionLoading component

Hi There !

I’m currently working on a login page with the sessionService Redux API.
I want showing the ionLoading component while the token isn’t store in the localStorage, it’s works but I’ve this error message in my console. I’m trying some cleanup function but I haven’t find a solution.
Here my code :

/* Import Authentication and Redux stack */
import { connect } from "react-redux";
import { loginUser } from "../../redux/authentication/actions/loginUser";
import { Link, useHistory } from "react-router-dom";

/* Import React Hooks */
import { useEffect, useState } from "react";

/* Import Formik and Formik Form */
import { Formik, Form } from "formik";

/* Import Initial Values for Form */
import { INIT_VALUES_LOGIN } from "../../constants/initialValues.login";

/* Import LoginSchema Validation */
import { loginSchema } from "../../validation/login.schema";

/* Import Components */
import TypePasswordSwitch from "../../components/Type.Password.Switch/Type.Password.Switch";

/* Import Ionic components */
import {
    IonList,
    IonGrid,
    IonRow,
    IonCol,
    IonItem,
    IonLabel,
    IonInput,
    IonButton,
    IonTitle,
    IonImg,
    IonCheckbox,
    IonIcon,
    IonLoading,
} from "@ionic/react";

/* Import CSS */
import Style from "./Login.module.scss";

/* Import Ionic icons */
import { help } from "ionicons/icons";

/* Import Logo */
import LogoRose from "../../assets/img/azuracom_rose.png";

/* Import Interface and Type Values */
import { ILoginUserFormValues } from "../../interfaces/interfaces";
import ModalError from "../../components/Modal.Error/Modal.Error";

const Login: React.FC<{ loginUser: Function }> = ({ loginUser }) => {
    const history = useHistory();
    const [showPassword, setShowPassword] = useState<boolean>(false);
    const [showModalError, setShowModalError] = useState<boolean>(false);
    const [showLoading, setShowLoading] = useState<boolean>(false);

    /* useEffect to handling the IonLoading async component and cleaning this component */
    useEffect(() => {
        if (showLoading && localStorage.getItem("token")) {
            setShowLoading(false);
        }
    }, [showLoading]);

    return (
        <div className={Style.form__container}>
            <ModalError
                showModalError={showModalError}
                setShowModalError={setShowModalError}
                modifiedData="Connection"
            />
            <IonImg src={LogoRose} className={Style.form__container__logo} />
            <Formik
                initialValues={INIT_VALUES_LOGIN}
                validationSchema={loginSchema}
                onSubmit={async (
                    values: ILoginUserFormValues,
                    { setSubmitting, setFieldError }
                ) => {
                    await loginUser(
                        values,
                        history,
                        setFieldError,
                        setSubmitting,
                        setShowModalError
                    );
                }}
            >
                {({
                    values,
                    errors,
                    touched,
                    handleSubmit,
                    handleChange,
                    isSubmitting,
                }) => (
                    <Form
                        onSubmit={handleSubmit}
                        className={Style.form__container__card}
                    >
                        <IonList className={Style.form__container__card__content}>
                            <IonGrid>
                                <IonRow>
                                    <IonCol>
                                        <IonTitle className={Style.form__container__card__title}>
                                            Se Connecter
                                        </IonTitle>
                                    </IonCol>
                                </IonRow>
                                <IonRow>
                                    <IonCol className={Style.form__container__card__email}>
                                        <IonItem>
                                            <IonLabel
                                                position="floating"
                                                className={Style.form__container__card__label}
                                            >
                                                Email
                                            </IonLabel>
                                            <IonInput
                                                id="email"
                                                name="email"
                                                placeholder="user@example.com"
                                                type="email"
                                                onIonChange={handleChange}
                                                value={values.email}
                                            />
                                        </IonItem>
                                    </IonCol>
                                </IonRow>
                                <div className={ Style.form__container__card__error}>
                                    {errors.email && touched.email && errors.email}
                                </div>
                                <IonRow>
                                    <IonCol className={Style.form__container__card__password}>
                                        <IonItem>
                                            <IonLabel
                                                position="floating"
                                                className={Style.form__container__card__label}
                                            >
                                                Mot de passe
                                            </IonLabel>
                                            <div className={Style.form__container__card__password__input}>
                                                <IonInput
                                                    id="password"
                                                    name="password"
                                                    type={showPassword ? "text" : "password"}
                                                    onIonChange={handleChange}
                                                    value={values.password}
                                                />
                                                <TypePasswordSwitch
                                                    setShowPassword={setShowPassword}
                                                    showPassword={showPassword}
                                                />
                                            </div>
                                        </IonItem>
                                    </IonCol>
                                </IonRow>
                                <div className={Style.form__container__card__error}>
                                    {errors.password && touched.password && errors.password}
                                </div>
                                <IonRow>
                                    <IonCol className={Style.form__container__card__forgot}>
                                        <Link
                                            className={Style.form__container__card__forgot__link}
                                            to="#"
                                        >
                                            <IonIcon
                                                icon={help}
                                                className={Style.form__container__card__forgot__icon}
                                                color="primary"
                                            />
                                            <IonLabel>
                                                Mot de passe oublié
                                            </IonLabel>
                                        </Link>
                                    </IonCol>
                                </IonRow>
                                <IonRow>
                                    <IonCol className={Style.form__container__card__remember}>
                                        <IonCheckbox
                                            name="remember"
                                            className={Style.form__container__card__remember__box}
                                        />
                                        <IonLabel>Se souvenir de moi</IonLabel>
                                    </IonCol>
                                </IonRow>
                            </IonGrid>
                            <IonButton
                                onClick={(event) => {
                                    event.preventDefault();
                                    setShowLoading(true);
                                }}
                                expand="block"
                                className={Style.form__container__card__button}
                                type="submit"
                                disabled={isSubmitting}
                                color="secondary"
                            >
                                Valider
                            </IonButton>
                            {/* Loader Component */}
                            <IonLoading
                                isOpen={showLoading}
                                onDidDismiss={() => setShowLoading(false)}
                                message={'Patientez...'}
                                duration={2000}
                            />
                        </IonList>
                    </Form>
                )}
            </Formik>
        </div>
    );
};

export default connect(null, { loginUser })(Login);

Error Message Console :

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.
    at Login (http://localhost:8100/static/js/main.chunk.js:11106:3)
    at ConnectFunction (http://localhost:8100/static/js/vendors~main.chunk.js:73095:75)
    at Route (http://localhost:8100/static/js/vendors~main.chunk.js:76262:29)

Greetings from France.
David

This might be caused because onDidDismiss is called whenever <IonLoading> is dismissed, including when it is dismissed because you found a token in your useEffect().

So, in the case of the token with your useEffect, the useEffect sets setShowLoading(false), and then IonLoading onDidDismiss() is triggered on stale state, causing the error.

Try it without the onDidDismiss() and see if you still get the same error.

1 Like

You save my day, I try without the onDidDismiss() and it works fine.
Thank you so much.