useState & useEffect 만들어보기

정소현·2024년 8월 21일
0

React

목록 보기
7/12
post-custom-banner

🌟 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)과의 조합. 즉, 함수가 생성될 당시의 외부 변수 및 상태를 '기억'하고, 이를 함수 호출 시에도 계속 접근할 수 있게 해줌

클로저의 기본 개념

  • 렉시컬 스코프(Lexical Scope): 자바스크립트는 코드 작성 위치에 따라 스코프가 결정 즉, 함수가 선언된 위치에 따라 해당 함수가 접근할 수 있는 변수들이 정의.
  • 클로저의 동작: 클로저는 내부 함수가 외부 함수의 변수에 접근할 수 있게 해주는 메커니즘. 일반적으로 함수가 실행되고 나면 그 함수의 변수들은 사라지지만, 클로저를 사용하면 이 변수들이 사라지지 않고 유지
post-custom-banner

0개의 댓글