"Uncaught TypeError: destroy is not a function" Error in React
Asked Answered
W

11

34

Now I'm building the application using React.js. All pages are working excepting of auth page. After logging successfully, it should bring the user to the home page but it was broken, and showed the blank page. After refreshing the manually, it started to show the home page.

When I checked the application thru development tools in the chrome browser, it says "Uncaught TypeError: destroy is not a function". I attached the code where caused the error.

...
const UnauthedWrapper = () => {
  const navigate = useNavigate();
  const location = useLocation();
  const {
    state: { auth, user },
  } = useContext(AppContext);

  useEffect(() => {
    if (auth && user && user.emailVerified && user.dstoreName) {
      navigate(`/app/overview`);
      return null;
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [auth, user]);

  return (
    <>
      {!location.pathname.includes("/auth") ? (
        <Header
          logo="/images/logo.png"
          page="landing"
          hideLogin={process.env.REACT_APP_ENV === "PROD"}
        />
      ) : (
        <Link to="/">
          <img
            src="/images/logo.png"
            alt="logo"
            className="logo ms-4 mt-4"
            width={180}
          />
        </Link>
      )}
     ...
Weiner answered 31/10, 2022 at 15:9 Comment(2)
Does this answer your question? Getting error after I put Async function in useEffectBolden
In my case I had mistakenly used useEffect instead of useMemoRidotto
C
34

It turns out this almost always happens when you try to return anything from your useEffect hook that is not a function.

  • Why Doesn’t This Work?

If you return anything from a useEffect function, it must be a function.

useEffect(() => {
    if (auth && user && user.emailVerified && user.dstoreName) {
      navigate(`/app/overview`);
      return null;
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [auth, user]);
  • The Quick Solution
  1. Remove the unnecessary return.
useEffect(() => {
    if (auth && user && user.emailVerified && user.dstoreName) {
      navigate(`/app/overview`);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [auth, user]);
  1. Make sure it has function.
useEffect(() => {
    if (auth && user && user.emailVerified && user.dstoreName) {
      navigate(`/app/overview`);
      return () => {}
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [auth, user]);
Carbolize answered 31/10, 2022 at 15:29 Comment(1)
"If you return anything from a useEffect function, it must be a function." - not true. You can return undefined or just nothing: return;. The no-op function () => {} is unnecessary.Kawai
P
45

In my case, I had the useEffect callback as an async function.

useEffect(async () =>{
 // code here...
},[])

So I created the function as a standalone and called it inside useEffect.

const doSomething = async() =>{
// code here...
}

useEffect(() =>{
 doSomething();
},[])
Pacien answered 5/6, 2023 at 13:45 Comment(1)
This was my case too. Turns out useEffect does not like that async keyword in its declaration.Brazen
C
34

It turns out this almost always happens when you try to return anything from your useEffect hook that is not a function.

  • Why Doesn’t This Work?

If you return anything from a useEffect function, it must be a function.

useEffect(() => {
    if (auth && user && user.emailVerified && user.dstoreName) {
      navigate(`/app/overview`);
      return null;
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [auth, user]);
  • The Quick Solution
  1. Remove the unnecessary return.
useEffect(() => {
    if (auth && user && user.emailVerified && user.dstoreName) {
      navigate(`/app/overview`);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [auth, user]);
  1. Make sure it has function.
useEffect(() => {
    if (auth && user && user.emailVerified && user.dstoreName) {
      navigate(`/app/overview`);
      return () => {}
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [auth, user]);
Carbolize answered 31/10, 2022 at 15:29 Comment(1)
"If you return anything from a useEffect function, it must be a function." - not true. You can return undefined or just nothing: return;. The no-op function () => {} is unnecessary.Kawai
K
5

The best answer is to return without any return value.

return;

Or in your case:

  useEffect(() => {
    if (auth && user?.emailVerified && user?.dstoreName) {
      navigate(`/app/overview`);
    }
  }, [auth, user?.emailVerified, user?.dstoreName]);

Notice that I have no return statement at all. Or you can use a guard clause:

  useEffect(() => {
    if (!auth || !user?.emailVerified || !user?.dstoreName) return;
    navigate(`/app/overview`);
  }, [auth, user?.emailVerified, user?.dstoreName]);

React is just a layer over JavaScript, so when a function has no return statement, or the value-less return statement (usually as part of a conditional), it returns undefined.

This is functionally equivalent to the explicit return undefined;, and React will ignore any undefined destroy function. But it will complain if you return null as a destroy function, because null in JavaScript is a defined value.

PS: I removed // eslint-disable-next-line react-hooks/exhaustive-deps because you can check the properties of user object for changes, instead of checking the user object. It's actually less prone to bugs that way because you compare actual values, not the object reference. It's possible to change the properties of an existing object without changing the reference, which would not fire the hook. That's the reason why ESLint warns you about Exhaustive Deps!


How did I get here? In my case I hit this problem because I tried to write a useEffect hook like this: useEffect(() => myAsyncFunc(myVal), [myVal]); but it wouldn't work because myAsyncFunc returns a Promise which cannot be a destroy function. The fix is to wrap myAsyncFunc(myVal) in curly braces {} which ensures it returns undefined:

useEffect(() => {
  myAsyncFunc(myVal);
}, [myVal]);
Kawai answered 16/3, 2023 at 6:52 Comment(0)
T
4

This error occurs because your "destroy" or "componentWillUnmount" returned by the callback in useEffect is not a function:

  useEffect(() => {
    if (auth && user && user.emailVerified && user.dstoreName) {
      navigate(`/app/overview`);
      return null; // NOT A FUNCTION
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [auth, user]);

So you'll have to change that to something that is a function, or don't return there at all.

  useEffect(() => {
    if (auth && user && user.emailVerified && user.dstoreName) {
      navigate(`/app/overview`);
      return () => {}; // no-op
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [auth, user]);
Tim answered 31/10, 2022 at 15:20 Comment(1)
"you'll have to change that to something that is a function, or don't return there at all" - not true. You can return undefined or just nothing: return;. The no-op function () => {} is unnecessary.Kawai
C
3

I just removed async from useEffect and it worked for me. This was the code which was giving the same error.

useEffect(async () => {
    if (!localStorage.getItem(process.env.REACT_APP_LOCALHOST_KEY)) {
        navigate("/login");
    }
}, []);
Culbert answered 16/9, 2023 at 18:17 Comment(0)
H
3

if you're write Direct async in useEffect: Putting async directly in useEffect() can lead to unexpected behavior and errors, especially when updating state within it.

const abc = ({children}) => {
const [user,setUser]=useState(undefined);
 

useEffect(async()=>{
    try {
        const activeUser = await currentUser({})
        console.log(activeUser);
        setUser({...activeUser})
        
    } catch (error) {
        console.log(error);
    }
}

},[])

with in a state updates inside async: React has strict rules about state updates with in hooks. Updating user state directly within the async function might violate those rules,use the:

Create an inner async function takeTime(){} within useEffect. Call load explicitly to ensure proper execution and asunc state updates like .

const  abc = ({children}) => {
const [user,setUser]=useState(undefined);
 

useEffect(()=>{


async function takeTime(){
    try {
        const activeUser = currentUser({})
        console.log(activeUser);
        setUser({...activeUser})
        
    } catch (error) {
        console.log(error);
        setUser(undefined)
    }
}

takeTime();// Call the await function to initiate user fetching

},[])
Headphone answered 12/2 at 1:48 Comment(1)
This was the issue i was facing when I migrated from react-scripts to vite recently. I knew it is not a good practice to use async useEffect but react-scripts didn't have any issues. I converted all the useEffect as in the example of this codeTeriann
C
1

just remove the return if there is not a function to return, in my case I had a useEffect for a reduce dispatch and I just removed the return and it fixed it:

useEffect(()=> {
   dispatch(fetchPostsAction())
  }, [dispatch])

There is no return

Cubbyhole answered 7/5, 2023 at 7:25 Comment(1)
This will not work if the author needs to return something; there is already an accepted answer, more clear and effective. Please read how to answerScolex
O
0
const check = ()=>{
   if (auth && user && user.emailVerified && user.dstoreName) {
      navigate(`/app/overview`);
      return () => {}
    }
}

useEffect(() => {
  check()
        // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [auth, user]);

put the code you have in useEffect as it own function

Ottilie answered 16/2, 2023 at 16:18 Comment(0)
D
0

I had the same error and, in my case, there was an useEffect without the {}:

   useEffect(() => 
        condition
          ? functionA()
          : functionB()
   , []);

so it was returning an object instead of a function (which is the only allowed return type). After adding {}, the error stopped.

   useEffect(() => {
     condition
          ? functionA()
          : functionB()
   }, []);
Derian answered 22/5 at 21:44 Comment(0)
S
0

"Uncaught TypeError: destroy is not a function" Error in React while using Firebase Google Authentication"

As for me I was working on google authentication with firebase. This error popped up when I tried to run useEffect as asynchronous function

useEffect(async()=>{
  const response = await getRedirectResult(auth);

  if (response) {
    const userDocRef = await createDocumentUserFromAuth(response.user);
  }

}

I changed this to like this

const getGoogleAuthRedirect = async () => {
   const response = await getRedirectResult(auth);

   if (response) {
     const userDocRef = await createDocumentUserFromAuth(response.user);
   }
};

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

After seperating the function and executing it inside useEffect error got resolved.

Sherrer answered 19/6 at 6:32 Comment(0)
L
-3

The simple solution for this is Instead of using useEffect please use useState

I had also stucked with this and got solution

happy coding...!

Laurentian answered 10/7, 2023 at 10:54 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Quintinquintina
The solution you provided is incorrect, as useEffect and useState are two different react hooks and are used for different use cases.Crambo

© 2022 - 2024 — McMap. All rights reserved.