🌟 useState와 useEffect를 원리를 이해하고 직접 만들어보았다.
React.mjs
let hooks = [];
let currentHook = 0;
const useState = (initialValue) => {
// 초기값 세팅
// 값이 없다면 초기값을 넣어줌
hooks[currentHook] = hooks[currentHook] || initialValue;
const hookIndex = currentHook;
// 실제 넣어줘야 하는 새로운값이 들어오면 값을 따로 받아줌(원래의 값에 영향받지 않기 위해서)
const setState = (newState) => {
if (typeof newState === "function") {
hooks[hookIndex] = newState(hooks[hookIndex]);
} else {
hooks[hookIndex] = newState;
}
};
// 하나의 값에 접근하여 변경 반환을 해준 후 다음으로 넘어감
return [hooks[currentHook++], setState];
};
useState();
useEffect(() => {}, []);
// 이전 Array와 현재 Array를 가져와 비교 후 변경
const useEffect = (callback, depArray) => {
const hasNoDeps = !depArray;
// 이전 deps를 가져오기 deps있는지 확인 있으면 deps 없으면 undefined
const prevDeps = hooks[currentHook] ? hooks[currentHook].deps : undefined;
const prevCleanup = hooks[currentHook]
? hooks[currentHook].cleanup
: undefined;
//변경사항이 있는지 확인 every로 한개씩 순회
const hasChangedDeps = prevDeps
? !depArray.every((el, i) => el === prevDeps[i])
: true; // 초기에는 값이 없으니까 무조건 실행 (값이 없으면 실행)
//변화가 어
if (hasNoDeps || hasChangedDeps) {
if (prevCleanup) prevCleanup(); // 만약 Cleanup함수가 있다면 먼저 시행
const cleanUp = callback(); // 그 다음 지금 콜백을 시행
hooks[currentHook] = { deps: depArray, cleanUp }; // 지금 콜백의 반환값을 다음 시행될 때는 적용되도록 넣어줌
}
currentHook++; // 다음번 hook으로 넘어감
};
const MyReact = {
render(Component) {
const instance = Component();
instance.render();
currentHook = 0;
return instance;
},
};
MyReact.useState = useState;
export { useState };
export default MyReact;
index.mjs
import MyReact from "./React.mjs";
function ExampleComponent() {
const [count, setCount] = useState();
const [text, setText] = useState("foo");
return {
click: () => setCount((prev) => prev + 1),
type: (text) => setText(text),
noop: () => setCount(count),
render: () => console.log("render", { count, text }),
};
}
let App = MyReact.render(ExampleComponent);
App.click();
App = MyReact.render(ExampleComponent);
이런 hook들이 마법처럼 일어나는 일이 아니라 미리 쓰여져있는 작동 함수들로 인해서 가능한 것이고
이것이 클로저라는 것도 알게 되었다.
클로저는 자바스크립트의 중요한 개념 중 하나로, 함수와 그 함수가 선언될 때의 렉시컬 환경(Lexical Environment)과의 조합. 즉, 함수가 생성될 당시의 외부 변수 및 상태를 '기억'하고, 이를 함수 호출 시에도 계속 접근할 수 있게 해줌
클로저의 기본 개념