sanket kheni
sanket kheni

Reputation: 1628

Error : Can't perform a React state update on an unmounted component

this is full error

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 SignUpPage

and this is my siguppage.js file

import React, { useState } from 'react'
import { withFirebase } from '../firebase/Context'
import { useHistory } from 'react-router-dom'
import { compose } from 'recompose'
import withAuthUser from '../UserData/withAuthUser'

const SignUpPage = (props) => {
    const [Email, setEmail] = useState('')
    const [PasswordOne, setPasswordOne] = useState('')
    const [PasswordTwo, setPasswordTwo] = useState('')
    const [UserName, setUserName] = useState('')
    const [error, setError] = useState('')
    let history = useHistory()
    const [AuthUser, setAuthUser] = props.AuthUser()

    const onSubmit = () => {
        props.firebase
            .createUserWithEmailAndPassword(Email, PasswordOne)
            .then((authUser) => {
                history.push('/home')
                setAuthUser(authUser)
            })
            .catch((error) => {
                setError(error)
                console.log(error)
            })
    }

    const IsInvalid =
        Email === '' ||
        PasswordOne === '' ||
        PasswordTwo === '' ||
        UserName === '' ||
        PasswordTwo !== PasswordOne

    return (
        <div>
            <h1>Sign Up</h1>

            <input
                type='text'
                placeholder='UserName'
                value={UserName}
                onChange={(UserName) => {
                    const { value } = UserName.target
                    setUserName(value)
                }}
            ></input>
            <input
                type='text'
                placeholder='email'
                value={Email}
                onChange={(Email) => {
                    const { value } = Email.target
                    setEmail(value)
                }}
            ></input>
            <input
                type='password'
                placeholder='PasswordOne'
                value={PasswordOne}
                onChange={(pass) => {
                    const { value } = pass.target
                    setPasswordOne(value)
                }}
            ></input>
            <input
                type='password'
                placeholder='PasswordTwo'
                value={PasswordTwo}
                onChange={(pass) => {
                    const { value } = pass.target
                    setPasswordTwo(value)
                }}
            ></input>
            <button disabled={IsInvalid} onClick={onSubmit} type='submit'>
                Submit
            </button>

            {error && <p>{error.message}</p>}
        </div>
    )
}

export default compose(withFirebase, withAuthUser)(SignUpPage)

I have used HOC for this, I passed the props.AuthUser via withAuthUser something like this

const withAuthUser = (Component) => (props) => {
    return (
        <AuthUserContext.Consumer>
            {(AuthUser) => <Component {...props} AuthUser={AuthUser}></Component>}
        </AuthUserContext.Consumer>
    )
}

AuthUser is a function

export const Value = () => {
    const [AuthUser, setAuthUser] = useState(null)
    return [AuthUser, setAuthUser]
}

and I passed this function to Provider usign context in main index.js

So I am trying to update state of AuthUser by calling props.setAuthUser but it gives this error..

Upvotes: 5

Views: 14078

Answers (3)

Atanas Vihrogonov
Atanas Vihrogonov

Reputation: 59

An unmounted component is your SignUpPage component. Find the way to stop the onSubmit when the component using it on mounts. First of all, run a cleanup function when the component that uses this function and this onSubmit on mounts, so place the cleanup function inside onSubmit and return it so return a value inside useEffect and that value is a function and then when the component that uses this useEffect it fires that returned cleanup function. You can create something like AbortController() catching the error and updating state.

Upvotes: 0

Adil Khalil
Adil Khalil

Reputation: 2131

You are trying to set state on an unmounted component.

const onSubmit = () => {
  props.firebase
    .createUserWithEmailAndPassword(Email, PasswordOne)
    .then((authUser) => {
      history.push("/home"); //This causes the current component to unmount
      setAuthUser(authUser); //This is an async action, you are trying to set state on an unmounted component.
    })
    .catch((error) => {
      setError(error);
      console.log(error);
    });
};

Upvotes: 3

Kartikey
Kartikey

Reputation: 5002

This error arises when you try to update a state inside a screen after you have left the screen. To fix this we need a cleanup function using useEffect hook

So your SignupPage.js should look like this

import React, { useEffect, useState } from "react";
import { withFirebase } from "../firebase/Context";
import { useHistory } from "react-router-dom";
import { compose } from "recompose";
import withAuthUser from "../UserData/withAuthUser";

const SignUpPage = (props) => {
  const [Email, setEmail] = useState("");
  const [PasswordOne, setPasswordOne] = useState("");
  const [PasswordTwo, setPasswordTwo] = useState("");
  const [UserName, setUserName] = useState("");
  const [error, setError] = useState("");
  let history = useHistory();
  const [AuthUser, setAuthUser] = props.AuthUser();

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

  const onSubmit = () => {
    props.firebase
      .createUserWithEmailAndPassword(Email, PasswordOne)
      .then((authUser) => {
        history.push("/home");
        setAuthUser(authUser);
      })
      .catch((error) => {
        setError(error);
        console.log(error);
      });
  };

  const IsInvalid =
    Email === "" ||
    PasswordOne === "" ||
    PasswordTwo === "" ||
    UserName === "" ||
    PasswordTwo !== PasswordOne;

  return (
    <div>
      <h1>Sign Up</h1>

      <input
        type="text"
        placeholder="UserName"
        value={UserName}
        onChange={(UserName) => {
          const { value } = UserName.target;
          setUserName(value);
        }}
      ></input>
      <input
        type="text"
        placeholder="email"
        value={Email}
        onChange={(Email) => {
          const { value } = Email.target;
          setEmail(value);
        }}
      ></input>
      <input
        type="password"
        placeholder="PasswordOne"
        value={PasswordOne}
        onChange={(pass) => {
          const { value } = pass.target;
          setPasswordOne(value);
        }}
      ></input>
      <input
        type="password"
        placeholder="PasswordTwo"
        value={PasswordTwo}
        onChange={(pass) => {
          const { value } = pass.target;
          setPasswordTwo(value);
        }}
      ></input>
      <button disabled={IsInvalid} onClick={onSubmit} type="submit">
        Submit
      </button>

      {error && <p>{error.message}</p>}
    </div>
  );
};

export default compose(withFirebase, withAuthUser)(SignUpPage);

Try this and let me know.

Upvotes: 4

Related Questions