-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathreact-render-phases.js
More file actions
114 lines (99 loc) · 3.08 KB
/
react-render-phases.js
File metadata and controls
114 lines (99 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/**
* 🧠 Concept: React Render Phases – Render & Commit
*
* ---------------------------------------------------------
* 📘 Definition:
* React’s rendering process is split into two main **phases**:
*
* 1. **Render Phase**:
* - Pure & side-effect-free.
* - Determines **what to render**.
* - Can be paused, aborted, and restarted by React (especially in Concurrent Mode).
*
* 2. **Commit Phase**:
* - Applies DOM updates.
* - Executes side effects (`useEffect`, `useLayoutEffect`, refs, etc).
* - This phase is **not interruptible**.
*
* ---------------------------------------------------------
*
* 🔄 FLOW OF A RENDER CYCLE (Functional Component):
*
* ➤ Function Component Runs → JSX → React Element
* ➤ Reconciliation (diffing virtual DOM)
* ➤ Commit DOM changes
* ➤ Run effects (useEffect/useLayoutEffect)
*
* ---------------------------------------------------------
*
* 🔍 Render Phase Details:
*/
function ExampleComponent({ count }) {
console.log("🖊️ Render phase: Component running");
// No DOM side-effects here!
// DON'T: document.querySelector, timers, subscriptions, etc
return (
<div>
<p>Count is: {count}</p>
</div>
);
}
/**
* React can run this render multiple times
* without committing changes if needed.
* e.g., StrictMode intentionally runs components twice in dev
*/
/**
* ---------------------------------------------------------
* 🔥 Commit Phase Example with useEffect & useLayoutEffect:
*/
import { useEffect, useLayoutEffect } from "react";
function Demo() {
useEffect(() => {
console.log("✅ useEffect (runs in commit phase - after paint)");
}, []);
useLayoutEffect(() => {
console.log("🛠️ useLayoutEffect (runs in commit phase - before paint)");
}, []);
console.log("🖊️ Rendering...");
return <div>Open the console and check logs!</div>;
}
/**
* Output (DOM painted after useLayoutEffect):
* 🖊️ Rendering...
* 🛠️ useLayoutEffect (before paint)
* ✅ useEffect (after paint)
*/
/**
* ---------------------------------------------------------
* 🧪 Real-World Use Case:
*
* 🔹 useEffect: Good for API calls, timers, event listeners.
* 🔹 useLayoutEffect: Needed when measuring DOM size before paint.
*
* Example:
*/
useLayoutEffect(() => {
const width = document.getElementById("box").offsetWidth;
console.log("Box width before painting:", width);
});
/**
* ---------------------------------------------------------
* 🧵 React Fiber (Concurrent Rendering engine)
*
* In Concurrent Mode:
* - React may "pause" work in Render Phase.
* - It can throw away a render and re-render again.
* - Commit Phase is always atomic and consistent.
*
* ⚠️ So: avoid side-effects in render logic!
*/
/**
* ✅ Summary:
* ------------------------------
* 🔸 Render Phase → Prepare UI (pure, side-effect-free)
* 🔸 Commit Phase → Apply UI (DOM mutations, effects, refs)
* 🔸 useEffect/useLayoutEffect → Commit phase tools
* 🔸 React may discard renders, but never commits
* 🔸 Always treat render as a pure function
*/