according to the doc
If you’re migrating code from a class component, note
useLayoutEffectfires in the same phase ascomponentDidMountandcomponentDidUpdate. However, we recommend starting withuseEffectfirst and only tryinguseLayoutEffectif 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.
React Hooks and Component Lifecycle Equivalent
How to use componentWillMount() in React Hooks?
What is determining the order in which these components' 'mount' functions execute?
useLayoutEffect in ssr
Videos
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?
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>
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.
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
useEffectHook ascomponentDidMount,componentDidUpdate, andcomponentWillUnmountcombined.
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)
}
}, [])
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.
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:
- Component renders for the first time.
- The return value of render() is used to mount new DOM.
- componentDidMount fires and sets state immediately (not in an async callback)
- The state change means render() is called again and returns new JSX which replaces the previous render.
- 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:
The console.logs in the render functions, in order from parent to child, since part of rendering each component is rendering the children
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).
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"/>
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
Hook useEffect runs asynchronously and usually after the DOM is rendered / mounted, whereas useLayoutEffect runs synchronously and before the DOM is rendered / mounted.
Both of them occur after the changes have been put onto the DOM. What's special about layout effects is that if you set state during the layout effect, the resulting render will be done synchronously. For normal effects, if you set state, it will rerender soon, but not synchronously. If you never set state (as in your example), it's not going to make much difference which one you use.
The most common application of useLayoutEffect is that you want to render once, measure the stuff on the dom, and then render again without the user seeing the temporary stuff you had on the dom.
Check that your babel.config.js has the runtime set to automatic:
Copy"plugins": [
["@babel/plugin-transform-react-jsx", {
"runtime": "automatic"
}]
]
I also faced with this problem and my solution is to create internal state that will be set when the DOM is re-rendered, see the following code to understand:
const [rerender, setRerender] = useState(); // or any state
const [afterRender, setAfterRender] = useState();// internal state
// (1)
useEffect(() => {
if (!afterRender) return;
// here DOM is loaded and you can query DOM elements
// then reset
setAfterRender(false);
}, [afterRender]);
useEffect(() => {
setAfterRender(true); // (1) will be called after DOM rendered
}, [rerender]); // or don't set any if you want to listen to all re-render events
return {
setRerender, // expose function trigger re-render data
}
Updated in 2021 (React version 17.0.2)
useEffect will run after DOM loaded and UI paint (just useLayoutEffect run before UI paint).
It run in order:
- DOM manipulation.
- useLayoutEffect
- UI paint
- useEffect
It works on both componentDidMount and componentDidUpdate lifecycle.
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.
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.
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.
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
From what I've read, it appears to be known that:
All useLayoutEffects are always called before any useEffect
Multiple useEffects in one component are called in the order in which they are created
Any useLayoutEffect is called after all useLayoutEffects in child components, during one commit.
But some things are not clear:
When, exactly, is useEffect called? Does is use some browser API like requestIdleCallback?
Can / must useEffect in a child fire before useLayoutEffect in parent?
Are the "known" points actually guaranteed by React, or just an implementation detail?
Any feedback, links, related GitHub discussions, source code links appreciated!