according to the doc

If you’re migrating code from a class component, note useLayoutEffect fires in the same phase as componentDidMount and componentDidUpdate. However, we recommend starting with useEffect first and only trying useLayoutEffect if that causes a problem.

So if you want your side effect to run in a class component with the same behaviour you gotta use componentDidMount and componentDidUpdate like you thought. The difference between useEffect and useLayoutEffect is that useEffect only runs after the DOM has been updated (the effect will run after the render is committed to the screen). useLayoutEffect will trigger the effect right after the DOM mutations are computed. Therefore, updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint.

Here there's a good explanation about useEffect and useLayoutEffect. But thinking on class components, it's equivalent to componentDidMount and componentDidUpdate because it is the commit phase. That's the phase where changes to DOM are allowed to happen as well as side effects and scheduled updates. Both componentDidMount and componentDidUpdate have the synchronous behaviour just like useLayoutEffect. useEffect is the usual recommended option because it won't block the browser rendering which is better for performance in most cases, being an optimized hook version of componentDidMount and componentDidUpdate.

Answer from Thamy Bessa on Stack Overflow
🌐
Reacttraining
reacttraining.com › blog › useEffect-is-not-the-new-componentDidMount
useEffect(fn, []) is not the new componentDidMount()
January 31, 2020 - However useEffect runs after the paint has been committed to the screen as opposed to before. This means you would get a flicker if you needed to read from the DOM, then synchronously set state to make new UI. ... useLayoutEffect was designed to have the same timing as componentDidMount.
Discussions

React Hooks and Component Lifecycle Equivalent
What are the equivalents of the componentDidMount, componentDidUpdate, and componentWillUnmount lifecycle hooks using React hooks like useEffect? More on stackoverflow.com
🌐 stackoverflow.com
How to use componentWillMount() in React Hooks?
In the official docs of React it mentions - If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and More on stackoverflow.com
🌐 stackoverflow.com
What is determining the order in which these components' 'mount' functions execute?
In my code, app is the highest (functional) component. It renders piggybank (which is a class component) which renders piggychild (which is a functional component). Each component 'console.logs' th... More on stackoverflow.com
🌐 stackoverflow.com
useLayoutEffect in ssr
Hi, I do not understand the situation with this hook a bit. I use this hook to perform the animation synchronously with the state update, if I use useEffect, then I have jumps in the animation, bec... More on github.com
🌐 github.com
62
February 22, 2019
🌐
Reddit
reddit.com › r/reactjs › react documentation on uselayouteffect makes me confused
r/reactjs on Reddit: React documentation on useLayoutEffect makes me confused
June 27, 2023 -

The legacy documentation has the following note about the useLayoutEffect hook:

If you’re migrating code from a class component, note useLayoutEffect fires in the same phase as componentDidMount and componentDidUpdate. However, we recommend starting with useEffect first and only trying useLayoutEffect if that causes a problem.

And it makes me confused. Both componentDidMount and componentDidUpdate run after render method in a class component. This makes me think that code inside both componentDid... lifecycle methods will run after the UI is already rendered on a screen.

And useLayoutEffect has this in the description:

Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint

Which means "before UI s rendered on a screen", doesn't it? Then how is this possible?

useLayoutEffect fires in the same phase as componentDidMount and componentDidUpdate

Or did I get something wrong?

🌐
Kent C. Dodds
kentcdodds.com › blog › useeffect-vs-uselayouteffect
useEffect vs useLayoutEffect
This can be useful if you need to make DOM measurements (like getting the scroll position or other styles for an element) and then make DOM mutations or trigger a synchronous re-render by updating state. As far as scheduling, this works the same way as componentDidMount and componentDidUpdate.
🌐
React
legacy.reactjs.org › docs › hooks-reference.html
Hooks API Reference – React
If you’re migrating code from a class component, note useLayoutEffect fires in the same phase as componentDidMount and componentDidUpdate.
🌐
GeeksforGeeks
geeksforgeeks.org › reactjs › reactjs-uselayouteffect-hook
ReactJS useLayoutEffect Hook - GeeksforGeeks
July 23, 2025 - But to prevent blocking the page loading, we should always use the useEffect hook. ... The useLayoutEffect hook works in the same phase as componentDidMount and componentDidUpdate methods.
Top answer
1 of 4
64

componentDidMount

Pass an empty array as the second argument to useEffect() to run only the callback on mount only.

function ComponentDidMount() {
  const [count, setCount] = React.useState(0);
  React.useEffect(() => {
    console.log('componentDidMount');
  }, []);

  return (
    <div>
      <p>componentDidMount: {count} times</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <div>
    <ComponentDidMount />
  </div>,
  document.querySelector("#app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

componentDidUpdate

componentDidUpdate() is invoked immediately after updating occurs. This method is not called for the initial render. useEffect runs on every render including the first. So if you want to have a strict equivalent as componentDidUpdate, you have to use useRef to determine if the component has been mounted once. If you want to be even stricter, use useLayoutEffect(), but it fires synchronously. In most cases, useEffect() should be sufficient.

This answer is inspired by Tholle, all credit goes to him.

function ComponentDidUpdate() {
  const [count, setCount] = React.useState(0);

  const isFirstUpdate = React.useRef(true);
  React.useEffect(() => {
    if (isFirstUpdate.current) {
      isFirstUpdate.current = false;
      return;
    }

    console.log('componentDidUpdate');
  });

  return (
    <div>
      <p>componentDidUpdate: {count} times</p>
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <ComponentDidUpdate />,
  document.getElementById("app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

componentWillUnmount

Return a callback in useEffect's callback argument and it will be called before unmounting.

function ComponentWillUnmount() {
  function ComponentWillUnmountInner(props) {
    React.useEffect(() => {
      return () => {
        console.log('componentWillUnmount');
      };
    }, []);

    return (
      <div>
        <p>componentWillUnmount</p>
      </div>
    );
  }
  
  const [count, setCount] = React.useState(0);

  return (
    <div>
      {count % 2 === 0 ? (
        <ComponentWillUnmountInner count={count} />
      ) : (
        <p>No component</p>
      )}
      <button
        onClick={() => {
          setCount(count + 1);
        }}
      >
        Click Me
      </button>
    </div>
  );
}

ReactDOM.render(
  <div>
    <ComponentWillUnmount />
  </div>,
  document.querySelector("#app")
);
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

2 of 4
18

From React docs:

If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

By that saying they mean:

componentDidMount is sort of useEffect(callback, [])

componentDidUpdate is sort of useEffect(callback, [dep1, dep2, ...]) - the array of deps tell React: "if one of the deps is change, run the callback after rendering".

componentDidMount + componentDidUpdate is sort of useEffect(callback)

componentWillUnmount is sort of the returned function from the callback:

useEffect(() => { 
    /* some code */
    return () => { 
      /* some code to run when rerender or unmount */
    }
)

With the help of Dan Abramov's phrasing from his blog, and some additions of my own:

While you can use those hooks, it’s not an exact equivalent. Unlike componentDidMount and componentDidUpdate, it will capture props and state. So even inside the callbacks, you’ll see the props and state of the specific render (which means in componentDidMount the initial props and state). If you want to see “latest” something, you can write it to a ref. But there’s usually a simpler way to structure the code so that you don’t have to. The returned function which supposes to be alternative to componentWillUnmount also is not an exact equivalent, since the function will run every time the component will re-render and when the component will unmount. Keep in mind that the mental model for effects is different from component lifecycles, and trying to find their exact equivalents may confuse you more than help. To get productive, you need to “think in effects”, and their mental model is closer to implementing synchronization than to responding to lifecycle events.

Example from Dan's blog:

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setTimeout(() => {
      console.log(`You clicked ${count} times`);
    }, 3000);
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

If we use the class implementation:

componentDidUpdate() {
  setTimeout(() => {
    console.log(`You clicked ${this.state.count} times`);
  }, 3000);
}

this.state.count always points at the latest count rather than the one belonging to a particular render.

Find elsewhere
Top answer
1 of 16
757

You cannot use any of the existing lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount etc.) in a hook. They can only be used in class components. And with Hooks you can only use in functional components. The line below comes from the React doc:

If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

suggest is, you can mimic these lifecycle method from class component in a functional components.

Code inside componentDidMount run once when the component is mounted. useEffect hook equivalent for this behaviour is

useEffect(() => {
  // Your code here
}, []);

Notice the second parameter here (empty array). This will run only once.

Without the second parameter the useEffect hook will be called on every render of the component which can be dangerous.

useEffect(() => {
  // Your code here
});

componentWillUnmount is use for cleanup (like removing event listeners, cancel the timer etc). Say you are adding a event listener in componentDidMount and removing it in componentWillUnmount as below.

const mouseMoveHandler = () => {}

componentDidMount() {
  window.addEventListener('mousemove', mouseMoveHandler)
}

componentWillUnmount() {
  window.removeEventListener('mousemove', mouseMoveHandler)
}

Hook equivalent of above code will be as follows:

useEffect(() => {
  const mouseMoveHandler = () => {}

  window.addEventListener('mousemove', mouseMoveHandler);

  // returned function will be called on component unmount 
  return () => {
    window.removeEventListener('mousemove', mouseMoveHandler)
  }
}, [])
2 of 16
255

useComponentWillMount hook

const useComponentWillMount = (cb) => {
    const willMount = useRef(true)

    if (willMount.current) cb()

    willMount.current = false
}

This hook could be a saver when there is an issue of sequence (such as running before another script). If that isn't the case, use useComnponentDidMount which is more aligned with React hooks paradigm.

useComponentDidMount hook

const useComponentDidMount = cb => useEffect(cb, []);

If you know your effect should only run once at the beginning use this solution. It will run only once after component has mounted.

useEffect paradigm

Class components have lifecycle methods which are defined as points in the timeline of the component. Hooks don't follow this paradigm. Instead effects should be structured by their content.

function Post({postID}){
  const [post, setPost] = useState({})

  useEffect(()=>{
    fetchPosts(postID).then(
      (postObject) => setPost(postObject)
    )
  }, [postID])

  ...
}

In the example above the effect deals with fetching the content of a post. Instead of a certain point in time it has a value it is dependent on - postID. Every time postID gets a new value (including initialization) it will rerun.

Component Will Mount discussion

In class components componentWillMount is considered legacy (source 1, source2). It's legacy since it might run more than once, and there is an alternative - using the constructor. Those considerations aren't relevant for a functional component.

Top answer
1 of 2
2

useEffect has a different timing than componentDidMount. The hook that's closest to CDM is actually useLayoutEffect.

Here's a bit from ReactTraining's blog on useEffect:

They run at different times

First, let's talk about the timing of each. componentDidMount runs after the component mounts. As the docs say, if you set state immediately (synchronously) then React knows how to trigger an extra render and use the second render's response as the initial UI so the user doesn't see a flicker. Imagine you need to read the width of a DOM element with componentDidMount and want to update state to reflect something about the width. Imagine this sequence of events:

  1. Component renders for the first time.
  2. The return value of render() is used to mount new DOM.
  3. componentDidMount fires and sets state immediately (not in an async callback)
  4. The state change means render() is called again and returns new JSX which replaces the previous render.
  5. The browser only shows the second render to avoid flicker.

It's nice that this is how it works for when we need it. But most the time we don't need this pre-optimized approach because we're doing asynchronous network calls and then setting state after the paint to the screen.

componentDidMount and useEffect run after the mount. However useEffect runs after the paint has been committed to the screen as opposed to before. This means you would get a flicker if you needed to read from the DOM, then synchronously set state to make new UI.

How do get the old behavior back when we need it?

useLayoutEffect was designed to have the same timing as componentDidMount. So useLayoutEffect(fn, []) is a much closer match to componentDidMount() than useEffect(fn, []) -- at least from a timing standpoint.

Does that mean we should be using useLayoutEffect instead?

Probably not.

If you do want to avoid that flicker by synchronously setting state, then use useLayoutEffect. But since those are rare cases, you'll want to use useEffect most of the time.

I've added an example which has both Layout Effects and normal Effects in the scenario you described:

The results of running this are as follows. The main thing to note with this is that The Layout effects happen in a sensible order with the componentDidMount lifecycle hook, whereas the effects happen later.

App

PiggyBank

PiggyChild

PiggyChild LayoutEffect

PiggyBank Mount

App LayoutEffect

PiggyChild Effect

App Effect

const {useEffect, useLayoutEffect} = React;
function App(){
 console.log('App');
 useLayoutEffect(()=>console.log('App LayoutEffect'),[]);
 useEffect(()=>console.log('App Effect'),[]);

 return <PiggyBank/>;
}
class PiggyBank extends React.Component{
 componentDidMount(){
  console.log('PiggyBank Mount');
 }
 render(){
  console.log('PiggyBank');
  return <PiggyChild/>
 }
}
function PiggyChild(){
 console.log('PiggyChild');
 useLayoutEffect(()=>console.log('PiggyChild LayoutEffect'),[]);
 useEffect(()=>console.log('PiggyChild Effect'),[]);
 return <div/>;
}
ReactDOM.render(<App/>,document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"/>


Without the LayoutEffects, the order will be:

  1. The console.logs in the render functions, in order from parent to child, since part of rendering each component is rendering the children

  2. Then the componentDidMount runs immediately after it finishes mounting. If there are multiple components with componentDidMounts or useLayoutEffects, these would be called in order from from child to parent as they finish mounting, but before the paint is committed (as mentioned above).

  3. The useEffects run in order from child to parent as they finished mounting in that order, but they will always run after the componentDidMounts and useLayoutEffects due to the timing mentioned above.

const {useEffect} = React;
function App(){
 console.log('App');
 // useLayoutEffect(()=>console.log('App LayoutEffect'),[]);
 useEffect(()=>console.log('App Effect'),[]);

 return <PiggyBank/>;
}
class PiggyBank extends React.Component{
 componentDidMount(){
  console.log('PiggyBank Mount');
 }
 render(){
  console.log('PiggyBank');
  return <PiggyChild/>
 }
}
function PiggyChild(){
 console.log('PiggyChild');
 // useLayoutEffect(()=>console.log('PiggyChild LayoutEffect'),[]);
 useEffect(()=>console.log('PiggyChild Effect'),[]);
 return <div/>;
}
ReactDOM.render(<App/>,document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"/>

2 of 2
0

Actually it makes absolute sense, and order of useEffect in hierarchy is the same as in componentDidMount. The thing is that componentDidMount fires when all children mounted (so you would see first child event, and only then parent one) - so same order as you see.

For more details about order of componentDidMount you could see here - Order of componentDidMount in React components hierarchy

🌐
GitHub
github.com › facebook › react › issues › 14927
useLayoutEffect in ssr · Issue #14927 · facebook/react
February 22, 2019 - Also, the documentation states that useLayoutEffect runs on the same phase as componentDidMount (that is, on the client side), and here my server issues complaints to me about my code.
Author   dimensi
🌐
KnowledgeHut
knowledgehut.com › home › blog › web development › react uselayouteffect() - hook api reference in react
React useLayoutEffect() - Hook API Reference In React
April 25, 2024 - It works on the same principle as componentDidMount and componentDidUpdate in scheduling. Your function executing the DOM gets limited even before the browser has an opportunity to "paint" those adjustments; the user doesn't notice the changes ...
🌐
Medium
medium.com › @alexandereardon › uselayouteffect-and-ssr-192986cdcf7a
useLayoutEffect and SSR. How to get warning free usage of… | by Alex Reardon | Medium
April 29, 2019 - useLayoutEffectfires in the same phase as componentDidMount and componentDidUpdate — React Documentation
Top answer
1 of 2
4

A useEffect is the equivalent of componentDidMount, so it will run once when the component mounts, and then only re-run when one of the dependencies defined in the dependency array changes.

If you want to call getRecipes() only when the query dependency has a value, you can call it in a conditional like so:

useEffect(() => {
  if(query) {
    getRecipes()
  }
}, [query])

Also, as your useEffect is calling a function (getRecipes) that is declared outside the use effect but inside the component, you should either move the function declaration to be inside the useEffect and add the appropriate dependencies, or wrap your function in a useCallback and add the function as a dependency of the useEffect.

See the React docs for information on why this is important.

2 of 2
0

UseEffect hook work equivalent of componentDidMount, componentDidUpdate, and componentWillUnmount combined React class component lifecycles.but there is a different in time of acting in DOM.componentDidMount and useEffect run after the mount. However useEffect runs after the paint has been committed to the screen as opposed to before. This means you would get a flicker if you needed to read from the DOM, then synchronously set state to make new UI.useLayoutEffect was designed to have the same timing as componentDidMount. So useLayoutEffect(fn, []) is a much closer match to componentDidMount() than useEffect(fn, []) -- at least from a timing standpoint. Does that mean we should be using useLayoutEffect instead? Probably not. If you do want to avoid that flicker by synchronously setting state, then use useLayoutEffect. But since those are rare cases, you'll want to use useEffect most of the time.

Top answer
1 of 11
664

For the stable version of hooks (React Version 16.8.0+)

For componentDidMount

useEffect(() => {
  // Your code here
}, []);

For componentDidUpdate

useEffect(() => {
  // Your code here
}, [yourDependency]);

For componentWillUnmount

useEffect(() => {
  // componentWillUnmount
  return () => {
     // Your code here
  }
}, [yourDependency]);

So in this situation, you need to pass your dependency into this array. Let's assume you have a state like this

const [count, setCount] = useState(0);

And whenever count increases you want to re-render your function component. Then your useEffect should look like this

useEffect(() => {
  // <div>{count}</div>
}, [count]);

This way whenever your count updates your component will re-render. Hopefully this will help a bit.

2 of 11
53

There is no exact equivalent for componentDidMount in react hooks.


In my experience, react hooks requires a different mindset when developing it and generally speaking you should not compare it to the class methods like componentDidMount.

With that said, there are ways in which you can use hooks to produce a similar effect to componentDidMount.

Solution 1:

useEffect(() => {
  console.log("I have been mounted")
}, [])

Solution 2:

const num = 5

useEffect(() => {
  console.log("I will only run if my deps change: ", num)
}, [num])

Solution 3 (With function):

useEffect(() => {
  const someFunc = () => {
    console.log("Function being run after/on mount")
  }
  someFunc()
}, [])

Solution 4 (useCallback):

const msg = "some message"

const myFunc = useCallback(() => {
  console.log(msg)
}, [msg])

useEffect(() => {
  myFunc()
}, [myFunc])

Solution 5 (Getting creative):

export default function useDidMountHook(callback) {
  const didMount = useRef(null)

  useEffect(() => {
    if (callback && !didMount.current) {
      didMount.current = true
      callback()
    }
  })
}

It is worth noting that solution 5 should only really be used if none of the other solutions work for your use case. If you do decide you need solution 5 then I recommend using this pre-made hook use-did-mount.

Source (With more detail): Using componentDidMount in react hooks

🌐
Reddit
reddit.com › r/reactjs › when to use useeffect or uselayouteffect
r/reactjs on Reddit: When to use useEffect or useLayoutEffect
February 15, 2020 - From the react official docs: "Unlike componentDidMount and componentDidUpdate, the function passed to useEffect fires after layout and paint, during a deferred event.
🌐
Reddit
reddit.com › r/reactjs › when exactly are use(layout)effect hooks called?
r/reactjs on Reddit: When exactly are use(Layout)Effect hooks called?
April 16, 2021 -

From what I've read, it appears to be known that:

  1. All useLayoutEffects are always called before any useEffect

  2. Multiple useEffects in one component are called in the order in which they are created

  3. Any useLayoutEffect is called after all useLayoutEffects in child components, during one commit.

But some things are not clear:

  1. When, exactly, is useEffect called? Does is use some browser API like requestIdleCallback?

  2. Can / must useEffect in a child fire before useLayoutEffect in parent?

  3. Are the "known" points actually guaranteed by React, or just an implementation detail?

Any feedback, links, related GitHub discussions, source code links appreciated!

🌐
GitHub
github.com › facebook › react › issues › 14713
useLayoutEffect gets the initial state from useState instead of the current state when its input list never changes when an async method is fired · Issue #14713 · facebook/react
January 28, 2019 - When using useLayoutEffect (having it fire only once during mount, and once during unmount), setting state outside of it and then having an async method run inside of it, results in it not being able to useState as expected.
Author   itsdouges