처음 react hook을 사용했을 때부터, useState, useEffect와 같은 hook들이 내부적으로 어떻게 동작하는 지 매우 궁금했다. 사용하는 입장에서는 그저 마법처럼 느껴진다는 말이 맞는 것 같다.
사실, 이번 말고도 이전에 hook을 바닐라 js로 만드려다 실패한 적이 있다. 그래서 이번에는 가볍게 hook을 이해하고 동작하도록 만들어보려고 한다.
맨바닥부터 혼자 설계하여 이끌어내면 가장 좋겠지만, useState 만들기의 목적은 react hook의 내부 원리 및 동작을 간략하게나마 이해하는 것이 목적이기 때문에, 여러 reference를 참고하면서 진행한다.
const App = () => {
const [posts, setPosts] = useState([]);
const submitPost = (post) => () => {
setPosts([...posts, post]);
};
return `<div class="app">
${InputForm({ submitPost })}
${Todolist({ posts })}
</div>`;
};
짚고갈 점
const useState = (initState) => {
let state = initState;
const setState = (newState) => {
state = newState;
render();
}
return [state, setState];
}
⇒ 하지만, useState는 컴포넌트가 리렌더링 될때마다 계속해서 호출된다.
⇒ 따라서, 이전 상태를 기억하지 못하게 되고 초기 상태인지 구분할 수 없게 된다.
⇒ 당연히 상태는 계속 initState만 리턴한다.
let _state;
const useState = (initState) => {
if(_state === undefined) {
_state = initState;
}
const state = _state;
const setState = (newState) => {
_state = newState;
render();
}
return [state, setState];
}
let cursor = 0;
const states = [];
const useState = (initState) => {
let localCursor = cursor;
if (cursor === states.length) {
states.push(initState);
}
const state = states[cursor];
const setState = (newState) => {
states[localCursor] = newState;
render();
};
cursor += 1;
return [state, setState];
};
const render = () => {
const $root = document.getElementById("root");
cursor = 0;
$root.innerHTML = App();
};
let cursor = 0;
let _render;
const states = [];
export const useState = (initState) => {
let localCursor = cursor;
if (cursor === states.length) {
states.push(initState);
}
const state = states[cursor];
const setState = (newState) => {
states[localCursor] = newState;
_render();
};
cursor += 1;
return [state, setState];
};
const render = (GiactElement, $target) => {
_render = () => {
cursor = 0;
$target.innerHTML = GiactElement();
};
_render();
};
const Giact = { render };
export default Giact;
import Giact from "../core/Giact.js";
import App from "./App.js";
const $root = document.getElementById("root");
Giact.render(App, $root);
다음은 jsx를 이용하여 virtual DOM 까지 도입해보고자 한다.
Vanilla Javascript로 React UseState Hook 만들기
React hooks: not magic, just arrays