-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path20_Implement_useState.js
More file actions
87 lines (69 loc) · 2 KB
/
20_Implement_useState.js
File metadata and controls
87 lines (69 loc) · 2 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
/**
* 20. Implement a basic version of useState
*
* A simplified simulation of how React preserves state using closures and a global/module-level store.
*/
// Module pattern to simulate the React Runtime
const ReactPolyfill = (() => {
let hooks = []; // Stores states
let index = 0; // Current hook pointer
function useState(initialValue) {
const _idx = index; // Capture local index for THIS hook call
// If state doesn't exist (first render), initialize it
if (hooks[_idx] === undefined) {
hooks[_idx] = initialValue;
}
const setState = (newValue) => {
const val =
typeof newValue === "function" ? newValue(hooks[_idx]) : newValue;
hooks[_idx] = val;
render(); // Trigger re-render
};
index++; // Move to next hook for the next call in the component
return [hooks[_idx], setState];
}
function useEffect(cb, depArray) {
const oldDeps = hooks[index];
let hasChanged = true;
if (oldDeps) {
hasChanged = depArray.some((dep, i) => !Object.is(dep, oldDeps[i]));
}
if (hasChanged) {
cb();
}
hooks[index] = depArray;
index++;
}
// Reset index before every render so hooks align correctly
function workLoop() {
index = 0;
// In real React, this calls the component
}
return { useState, useEffect, workLoop };
})();
// Example Usage Simulation:
// Define Component
function Counter() {
const [count, setCount] = ReactPolyfill.useState(0);
const [text, setText] = ReactPolyfill.useState("foo");
console.log("Render:", { count, text });
return {
click: () => setCount(count + 1),
type: (txt) => setText(txt),
};
}
// Function to simulate render cycle
let App;
function render() {
ReactPolyfill.workLoop();
App = Counter();
}
// 1. Initial Render
render();
// Output: Render: { count: 0, text: 'foo' }
// 2. Update State
App.click();
// Inside setState -> calls render()
// Output: Render: { count: 1, text: 'foo' }
App.type("bar");
// Output: Render: { count: 1, text: 'bar' }