Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A React hook that tells if the component is mounted.
import React from 'react'
export const useIsMounted = () => {
const ref = React.useRef(false)
const [, setIsMounted] = React.useState(false)
React.useEffect(() => {
ref.current = true
setIsMounted(true)
return () => (ref.current = false)
}, [])
return () => ref.current
}
@timoxley

This comment has been minimized.

Copy link

@timoxley timoxley commented Jun 4, 2019

@jaydenseric why setIsMounted(true)

@jaydenseric

This comment has been minimized.

Copy link
Owner Author

@jaydenseric jaydenseric commented Jun 4, 2019

@timoxley I have since found ways to avoid having to use a useIsMounted hook, but from my rusty memory, the state is updated arbitrarily in the useEffect callback to trigger a re-render? I worked through a lot of gotchas to get it going.

@christiaanwesterbeek

This comment has been minimized.

Copy link

@christiaanwesterbeek christiaanwesterbeek commented Jun 7, 2019

Use this one instead: https://github.com/jmlweb/isMounted
It doesn't use state for this, which is good.

yarn add ismounted

@hieusmiths

This comment has been minimized.

Copy link

@hieusmiths hieusmiths commented Feb 14, 2020

Sorry, please expalain for me why use ref above.

i coded like this. it work welllll.

import React, { useState, useEffect } from "react";

export default () => {
const [mounted, setMounted] = useState(false);

useEffect(() => {
console.log("Run o day");
});

useEffect(() => {
console.log("Run");
}, []);
return () => mounted;
};

Thank so much

if you write like me, when your component didmount setState will re-render for set new state, so using ref. Thank you

@ivawzh

This comment has been minimized.

Copy link

@ivawzh ivawzh commented Jun 27, 2020

A better way and with explanation of how useEffect works:

export function useIsMounted(): { current: boolean } {
  // component is certainly mounted from the beginning
  const componentIsMounted = useRef(true)
  useEffect(() => {
  // when non-SSR + (ComponentDidMount or ComponentDidUpdate):
  // do nothing.
  // when non-SSR + ComponentWillUnmount:
    return () => { componentIsMounted.current = false }
  }, [])
  return componentIsMounted
}

And if you want it short =]

export function useIsMounted(): { current: boolean } {
  const componentIsMounted = useRef(true)
  useEffect(() => () => { componentIsMounted.current = false }, [])
  return componentIsMounted
}
@jaydenseric

This comment has been minimized.

Copy link
Owner Author

@jaydenseric jaydenseric commented Jun 27, 2020

@ivawzh "Mounted" usually refers to the component being rendered to the DOM in a browser. I can see how your hook could be useful though, maybe it would be better named something like useDidUnMount, and invert the boolean it returns.

@ivawzh

This comment has been minimized.

Copy link

@ivawzh ivawzh commented Jun 28, 2020

"Mounted" usually refers to the component being rendered to the DOM in a browser

@jaydenseric I think you have misunderstood something. My version of useIsMounted will return the same result of yours. Which is exactly what you said. I.e.

const isMounted = useIsMounted()
isMounted.current
// return true when the component is still mounted.
// return false when the component is unmounted.

Comparing to your original code, my version is different at

  1. no redundant state const [, setIsMounted] = React.useState(false).
  2. no redundant mutation at ComponentDidMount and ComponentDidUpdate events, as your ref.current = true .
@jaydenseric

This comment has been minimized.

Copy link
Owner Author

@jaydenseric jaydenseric commented Jun 28, 2020

My version of useIsMounted will return the same result of yours.

I don't think so?

  • Mine returns a function (returning boolean), yours returns a ref.
  • Doesn't yours result in true during SSR? Mine doesn't.

I came up with his hook over a year ago, so I can't remember all the gotchas properly - I faintly recall there were a few a lot of the published useIsMounted hooks didn't cover. In the time since, I have managed to completely avoid using this hook. I think I have used a similar pattern to your hook in the implementation of more complex hooks before.

@ivawzh

This comment has been minimized.

Copy link

@ivawzh ivawzh commented Jun 28, 2020

Mine returns a function (returning boolean), yours returns a ref.

Right, I missed that part. But that's just a minor interface difference. Yours is a function that a user will call () and then return ref.current; mine is returning ref, and then the user will call .current which also returns ref.current.

Doesn't yours result in true during SSR? Mine doesn't.

Yes. But I believe that's the right way to be. Component is actually mounted during SSR, it's just the didMount event is not fired until client-side React.hydrate(). E.g. if you have async data fetch in a component and consider isMounted as false during SSR, so that skip setting state after that async fetch, then the first page returned from SSR will not be complete. And that data from async fetch will not be SEO-able.

@zmeyc

This comment has been minimized.

Copy link

@zmeyc zmeyc commented Aug 3, 2020

Returning a function will trigger effects on each re-render if you're using it like this:

const isMounted = useIsMounted()
useEffect(() => {
  ...will be triggered on each re-render...
}, [isMounted])

Instead of returning a new instance of function each time, memoize it:

import { useCallback, useEffect, useRef } from 'react'

export const useIsMounted = (): (() => boolean) => {
  const isMounted = useRef(false)
  useEffect(() => {
    isMounted.current = true
    return function cleanup(): void {
      isMounted.current = false
    }
  }, [])
  const checker = useCallback((): boolean => {
    return isMounted.current
  }, [])
  return checker
}
@geoguide

This comment has been minimized.

Copy link

@geoguide geoguide commented Dec 12, 2020

I'm curious why React wouldn't do this in useState itself?

@jpodpro

This comment has been minimized.

Copy link

@jpodpro jpodpro commented Mar 12, 2021

@geoguide really trying to understand this myself.

@kopax-polyconseil

This comment has been minimized.

Copy link

@kopax-polyconseil kopax-polyconseil commented Jun 15, 2021

Do you guys have the unit test of the short way as well :)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment