import { useEffect, useState } from 'react'
function App() {
const [state, setState] = useState(0);
console.log(1);
queueMicrotask(() => {
console.log('inside queueMicrotask - 1');
});
useEffect(() => {
console.log(2);
}, [state]);
queueMicrotask(() => {
console.log('inside queueMicrotask - 2');
});
Promise.resolve().then(() => {
console.log(3);
});
setTimeout(() => {
console.log(4);
}, 0);
const onClick = () => {
console.log(5);
setState((num) => num + 1);
console.log(6);
};
return (
<div>
<button onClick={onClick} data-testid="action">
click me
</button>
</div>
);
}
export default App
The result is
1 2 inside queueMicrotask - 1 inside queueMicrotask - 2 3 4
I expected
1 inside queueMicrotask - 1 2 inside queueMicrotask - 2 3 4
How is it possible for the callback function of useEffect to be called before the callback of queueMicrotask? I was under the impression that the microtask queue has a very high priority in the Event Loop.
I was under the impression that the microtask queue has a very high priority in the Event Loop.
It's misleading to think that microtasks have any priority, the microtask queue is simply visited as soon as the JS call-stack is empty, even from inside a single task. They don't participate at all in the task-prioritization system.
So these results mean that the callback of useEffect
is called "synchronously", before the main script ends.
So basically you have the same as the below snippet:
function App() {
console.log("## begin App");
queueMicrotask(() => console.log("microtask"));
useEffect(() => console.log("effect"));
console.log("## end App");
}
const effects = [];
function useEffect(cb) {
effects.push(cb);
}
function render(elem) {
for (const effect of effects) {
effect();
}
}
function main() {
console.log("#### begin main");
const elem = App();
render(elem); // actually synchronous
console.log("#### end main");
}
main();
This can be verified by adding some debugger
statement and see that both the App
function and the useEffect
callback share a same synchronous caller in their call-stack.