├── .gitignore ├── 10-modularity ├── src │ ├── main.js │ ├── App.js │ ├── utils │ │ └── debounceFrame.js │ ├── components │ │ └── CounterAndMeow.js │ └── core │ │ └── MyReact.js └── index.html ├── 02-only-one-state └── index.html ├── 01-make-state-frame └── index.html ├── README.md ├── 03-multi-state-bug └── index.html ├── 05-no-state-change └── index.html ├── 06-dont-render-no-change └── index.html ├── 04-multi-state-success └── index.html ├── 07-unnecessary-render └── index.html ├── 08-refactor-rendering-by-debounce └── index.html └── 09-abstract-render └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | .DS_Store 4 | *.iml 5 | node_modules 6 | -------------------------------------------------------------------------------- /10-modularity/src/main.js: -------------------------------------------------------------------------------- 1 | import { render } from "./core/MyReact.js"; 2 | import { App } from "./App.js"; 3 | 4 | render(App, document.querySelector('#app')); 5 | -------------------------------------------------------------------------------- /10-modularity/src/App.js: -------------------------------------------------------------------------------- 1 | import { CounterAndMeow } from "./components/CounterAndMeow.js"; 2 | 3 | export const App = () => ` 4 |
5 | ${CounterAndMeow()} 6 |
7 | `; -------------------------------------------------------------------------------- /10-modularity/src/utils/debounceFrame.js: -------------------------------------------------------------------------------- 1 | export function debounceFrame (callback) { 2 | let nextFrameCallback = -1; 3 | return () => { 4 | cancelAnimationFrame(nextFrameCallback); 5 | nextFrameCallback = requestAnimationFrame(callback) 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /10-modularity/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | MyReact App 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /10-modularity/src/components/CounterAndMeow.js: -------------------------------------------------------------------------------- 1 | import { useState } from "../core/MyReact.js"; 2 | 3 | export function CounterAndMeow () { 4 | const [count, setCount] = useState(1); 5 | const [cat, setCat] = useState('야옹! '); 6 | 7 | function countMeow (newCount) { 8 | setCount(newCount); 9 | setCat('야옹! '.repeat(newCount)); 10 | } 11 | 12 | window.increment = () => countMeow(count + 1); 13 | window.decrement = () => countMeow(count - 1); 14 | 15 | return ` 16 |
17 |

고양이가 ${count}번 울어서 ${cat}

18 | 19 | 20 |
21 | `; 22 | } 23 | -------------------------------------------------------------------------------- /02-only-one-state/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 |
10 | 40 | 41 | -------------------------------------------------------------------------------- /01-make-state-frame/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 |
10 | 44 | 45 | -------------------------------------------------------------------------------- /10-modularity/src/core/MyReact.js: -------------------------------------------------------------------------------- 1 | import { debounceFrame } from "../utils/debounceFrame.js"; 2 | 3 | function MyReact () { 4 | const options = { 5 | currentStateKey: 0, 6 | renderCount: 0, 7 | states: [], 8 | root: null, 9 | rootComponent: null, 10 | } 11 | 12 | function useState (initState) { 13 | const { currentStateKey: key, states } = options; 14 | if (states.length === key) states.push(initState); 15 | 16 | const state = states[key]; 17 | const setState = (newState) => { 18 | states[key] = newState; 19 | _render(); 20 | } 21 | options.currentStateKey += 1; 22 | return [ state, setState ]; 23 | } 24 | 25 | const _render = debounceFrame(() => { 26 | const { root, rootComponent } = options; 27 | if (!root || !rootComponent) return; 28 | root.innerHTML = rootComponent(); 29 | options.currentStateKey = 0; 30 | options.renderCount += 1; 31 | }); 32 | 33 | 34 | function render (rootComponent, root) { 35 | options.root = root; 36 | options.rootComponent = rootComponent; 37 | _render(); 38 | } 39 | 40 | return { useState, render }; 41 | 42 | } 43 | 44 | export const { useState, render } = MyReact(); 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vanilla Javascript로 React UseState Hook 만들기 2 | 이 저장소는 `Vanilla Javascript로 React UseState Hook 만들기` 아티클에서 사용되는 코드를 모아놓는 용도로 사용되었습니다. 3 | 4 | - [01. state 틀 구성](https://junilhwang.github.io/simple-use-state/01-make-state-frame/index.html) 5 | - [02. 한 개의 state만 있을 경우](https://junilhwang.github.io/simple-use-state/02-only-one-state/index.html) 6 | - [03. 여러 개의 state가 있을 경우 버그 발생](https://junilhwang.github.io/simple-use-state/03-multi-state-bug/index.html) 7 | - [04. 여러 개의 state가 있을 경우 정상 작동](https://junilhwang.github.io/simple-use-state/04-multi-state-success/index.html) 8 | - [05. state 값이 동일할 경우](https://junilhwang.github.io/simple-use-state/05-no-state-change/index.html) 9 | - [06. state 값이 동일할 경우 렌더링 방지](https://junilhwang.github.io/simple-use-state/06-dont-render-no-change/index.html) 10 | - [07. 불필요한 render 발생](https://junilhwang.github.io/simple-use-state/07-unnecessary-render/index.html) 11 | - [08. debounce로 렌더링을 리팩토링](https://junilhwang.github.io/simple-use-state/08-refactor-rendering-by-debounce/index.html) 12 | - [09. render 추상화](https://junilhwang.github.io/simple-use-state/09-abstract-render/index.html) 13 | - [10. 모듈화](https://junilhwang.github.io/simple-use-state/10-modularity/index.html) 14 | -------------------------------------------------------------------------------- /03-multi-state-bug/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 |
10 | 58 | 59 | -------------------------------------------------------------------------------- /05-no-state-change/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 |
10 | 59 | 60 | -------------------------------------------------------------------------------- /06-dont-render-no-change/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 |
10 | 66 | 67 | -------------------------------------------------------------------------------- /04-multi-state-success/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 |
10 | 70 | 71 | -------------------------------------------------------------------------------- /07-unnecessary-render/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 |
10 | 67 | 68 | -------------------------------------------------------------------------------- /08-refactor-rendering-by-debounce/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 |
10 | 75 | 76 | -------------------------------------------------------------------------------- /09-abstract-render/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 |
10 | 92 | 93 | --------------------------------------------------------------------------------