I' learning about react hooks useEffect and I'm confused on the order of execution of useEffect. In the console it tells me that the ChildComponent "child ponent" console.log was executed first, then the "on mount" useEffect, and lastly the "parent ponent" was logged. I was expecting "on mount" to be logged first, then "parent ponent", and lastly the "child ponent". Can anyone explain why the child logs first, or why things execute this way?
Fields is a simple array of objects
const fields = [
{
id : 'month',
title : 'Month'
},
{
id : 'amount',
title : 'Amount'
},
{
id : 'year',
title : 'Year'
},
];
import React, { useEffect, useState } from 'react';
export default function ParentComponent(props) {
const [fields, setFields] = useState(props.fields || []);
useEffect(() => {
console.log('on mount');
}, []);
useEffect(() => {
console.log('parent ponent');
}, [fields]);
function randomString() {
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
}
return (
<div>
<button
onClick={() => setFields([...fields,...[{id: randomString(), title: randomString()}]])}
>Change field</button>
<ChildComponent fields={fields}/>
</div>
);
}
function ChildComponent(props) {
useEffect(() => {
console.log('child ponent')
}, [props.fields]);
return (<div>
{props.fields.map(({ id, title }) => <div key={id} className="field">{title}</div>)}
</div>)
}
I' learning about react hooks useEffect and I'm confused on the order of execution of useEffect. In the console it tells me that the ChildComponent "child ponent" console.log was executed first, then the "on mount" useEffect, and lastly the "parent ponent" was logged. I was expecting "on mount" to be logged first, then "parent ponent", and lastly the "child ponent". Can anyone explain why the child logs first, or why things execute this way?
Fields is a simple array of objects
const fields = [
{
id : 'month',
title : 'Month'
},
{
id : 'amount',
title : 'Amount'
},
{
id : 'year',
title : 'Year'
},
];
import React, { useEffect, useState } from 'react';
export default function ParentComponent(props) {
const [fields, setFields] = useState(props.fields || []);
useEffect(() => {
console.log('on mount');
}, []);
useEffect(() => {
console.log('parent ponent');
}, [fields]);
function randomString() {
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
}
return (
<div>
<button
onClick={() => setFields([...fields,...[{id: randomString(), title: randomString()}]])}
>Change field</button>
<ChildComponent fields={fields}/>
</div>
);
}
function ChildComponent(props) {
useEffect(() => {
console.log('child ponent')
}, [props.fields]);
return (<div>
{props.fields.map(({ id, title }) => <div key={id} className="field">{title}</div>)}
</div>)
}
Share
Improve this question
asked Sep 27, 2021 at 1:07
RobertRobert
10.4k20 gold badges89 silver badges140 bronze badges
1
- It’s practically the same order of event bubbling. First top-down for the rendering, then bottom-up for the mounting/effect execution. useEffect is not setTimeout, it’s more like event handling. – hackape Commented Sep 27, 2021 at 1:17
1 Answer
Reset to default 8It's the same as javascript event bubbling which means when it runs, it calls all the ParentComponent
functions, which will call and render ChildComponent
, once the inner-est function is called (child rendered) it will bubble up to the top again, which now the ParentComponent's
useEffect
kicks in and will be in order.
I have modified a bit your code, so you can see more the order I'm referring https://codesandbox.io/s/silly-jennings-9hwwv?file=/src/App.js