-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.tsx
More file actions
145 lines (129 loc) · 4.13 KB
/
app.tsx
File metadata and controls
145 lines (129 loc) · 4.13 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// ---- Library --- //
const React = {
createElement: (tag, props, ...children) => {
if (typeof tag === 'function') {
try {
return tag(props, ...children);
} catch ({ promise, key }) {
console.log("promise",promise);
console.log("key",key);
// Handle when this promise is resolved/rejected.
promise.then((value) => {
resourceCache[key] = value;
reRender();
});
// We branch off the VirtualDOM here
// now this will be immediately be rendered.
return { tag: 'h2', props: null, children: ['loading your image'] };
}
}
const el = {
tag,
props,
children,
};
return el;
},
};
const resourceCache = {};
const createResource = (asyncTask, key) => {
// First check if the key is present in the cache.
// if so simply return the cached value.
if(resourceCache[key]) return resourceCache[key];
throw { promise: asyncTask(), key };
}
const myAppState = [];
let myAppStateCursor = 0;
const useState = (initialState) => {
// get the cursor for this useState
const stateCursor = myAppStateCursor;
// Check before setting AppState to initialState (reRender)
myAppState[stateCursor] = myAppState[stateCursor] || initialState;
// console.log(
// `useState is initialized at cursor ${stateCursor} with value:`,
// myAppState
// );
const setState = (newState) => {
// console.log(
// `setState is called at cursor ${stateCursor} with newState value:`,
// newState
// );
myAppState[stateCursor] = newState;
// Render the UI fresh given state has changed.
reRender();
};
// prepare the cursor for the next state.
myAppStateCursor++;
// console.log(`stateDump`, myAppState);
return [myAppState[stateCursor], setState];
};
const reRender = () => {
// console.log('reRender-ing :)');
const rootNode = document.getElementById('myapp');
// reset/clean whatever is rendered already
rootNode.innerHTML = '';
// Reset the global state cursor
myAppStateCursor = 0;
// then render Fresh
render(<App />, rootNode);
};
// ---- Application ---
const App = () => {
const [name, setName] = useState('Arindam');
const [count, setCount] = useState(0);
const photo1 = createResource(getMyAwesomePic, 'photo1');
const photo2 = createResource(getMyAwesomePic, 'photo2');
return (
<div draggable>
<h2>Hello {name}!</h2>
<p>I am a pargraph</p>
<input
type="text"
value={name}
onchange={(e) => setName(e.target.value)}
/>
<h2> Counter value: {count}</h2>
<button onclick={() => setCount(count + 1)}>+1</button>
<button onclick={() => setCount(count - 1)}>-1</button>
<h2>Our Photo Album</h2>
<img src={photo1} alt="Photo" />
<img src={photo2} alt="Photo" />
</div>
);
};
// ---- Remote API ---- //
const photoURL = 'https://picsum.photos/200';
const getMyAwesomePic = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(photoURL), 1500);
});
};
// ---- Library --- //
const render = (el, container) => {
let domEl;
// 0. el의 타입이 문자열인지 확인
// 문자열이면 텍스트 노드로 처리해야 함
if (typeof el === 'string') {
// 실제 텍스트 노드 생성
domEl = document.createTextNode(el);
container.appendChild(domEl);
// 텍스트 노드는 자식이 없으므로 여기서 종료
return;
}
// 1. el에 해당하는 실제 DOM 요소 생성
domEl = document.createElement(el.tag);
// 2. props가 있다면 DOM 요소에 속성 설정
let elProps = el.props ? Object.keys(el.props) : null;
if (elProps && elProps.length > 0) {
elProps.forEach((prop) => (domEl[prop] = el.props[prop]));
}
// 3. 자식 노드들을 처리 (재귀적으로 렌더링)
if (el.children && el.children.length > 0) {
// 자식을 렌더링할 때 현재 생성한 domEl이 그 부모가 됨
el.children.forEach((node) => render(node, domEl));
}
// 4. 완성된 DOM 요소를 부모 container에 추가
container.appendChild(domEl);
};
// ---- Application --- //
render(<App />, document.getElementById('myapp'));