2 minute read

부스트캠프에서 마스터로 활동하고 계신 황준일님이 쓰신 Vanilla Javascript로 React UseState Hook 만들기를 먼저 읽고 읽으면 이해하기 수월합니다.

1. 개요

지난 포스팅에서 함수형 컴포넌트를 만들어 보았습니다. 하지만 이것으론 부족합니다. 그렇습니다. 우리가 만든 컴포넌트의 상태를 관리하기 위해서는 Hook이 필요합니다. 오늘은 먼저 리액트의 useState 훅의 원리에 대해 알아본 뒤 지난 시간에 만든 라이브러리에 useState 훅을 더해 보겠습니다.

2. useState 훅의 원리

리액트에서 useState 훅은 아래와 같이 사용됩니다.

useState 훅을 호출하면 state와 state를 변경하는 setState 함수가 배열의 형태로 반환되며, setState 함수를 호출하면 state가 변경되면서 컴포넌트가 재렌더링됩니다. 컴포넌트가 재렌더링되면서 useState 함수가 다시 한 번 호출되는데 state 값은 초기화되지 않습니다. 어떻게 이런 일이 가능한 걸까요? 그것은 state를 useState 함수 외부에서 관리하기 때문입니다.

아래와 같이 state를 useState 함수 내부에서 관리할 경우에는 useState가 호출될 때마다 state가 초기화되겠죠. 결국 화면에는 계속 0만 표시될 것입니다.

그래서 state는 useState 함수 외부에서 관리해야 합니다. 그리고 state는 한 개가 아니라 여러 개일 수 있으므로 state의 배열을 만들어 관리하도록 하겠습니다.

useState 함수 안에서 key가 states 배열의 길이보다 작다는 것은 재렌더링 중이라는 것을 의미합니다. 재렌더링을 할 때는 기존에 관리하던 상태가 있으므로 상태 배열에 값을 새로 넣지 않습니다. 이로써 상태가 초기화되는 것을 막을 수 있습니다.

또한, useState 함수가 실행될 때마다 currentStateKey가 1씩 증가하며 렌더링이 끝나면 currentStateKey가 초기화됩니다. 여기서 리액트 훅의 또 다른 중요한 특징을 발견할 수 있습니다.

React Hook은 항상 top level에서만 호출되어야 한다는 것입니다.

이 규칙은 컴포넌트가 재렌더링될 때 항상 동일한 순서로 Hook이 호출되는 것을 보장하기 위함입니다. 만약 렌더링할 때마다 Hook이 호출되는 순서가 달라진다면 위 states 배열에서 관리하는 상태들의 순서가 꼬이게 되어 이전에 참조하던 상태와 현재의 상태가 동일한 것인지 보장할 수 없게 됩니다.

3. 라이브러리 개발

(1) 폴더 구조

폴더 구조는 아래와 같습니다.

.
├── babel.config.json
├── index.html
├── package.json
└── src
    ├── App.js
    ├── core
    │   ├── internal
    │   │   ├── dom.js
    │   │   ├── root.js
    │   │   └── store.js
    │   ├── react-dom.js
    │   └── react.js
    └── index.js

아래 파일들은 이전 포스팅에서 개발한 것과 동일합니다.

  • babel.config.json
  • index.html
  • package.json
  • src/index.js
  • src/core/react-dom.js

(2) store 분리

위에서 본 states 배열을 여러 모듈에서 사용할 수 있도록 파일로 분리하겠습니다.

  • src/core/internal/store.js

(3) useState

react.js에 정의된 useState 함수에서는 위 store.js에 정의된 함수들을 사용해 states 배열에 상태를 담고 관리합니다.

  • src/core/react.js

(4) 이벤트 등록

  • src/App.js

위에서 window 전역 객체에 함수로 등록해 사용하던 EventListener를 onClick prop으로 전달하고 있습니다. 이를 위해 DOM Element에 attribute를 설정하는 코드가 달라져야 합니다.

  • src/core/internal/dom.js

(5) 재렌더링

상태 변화에 의해 재렌더링되는 것을 새로운 Root Element를 만들어 기존의 Root Element와 교체하는 것으로 구현하겠습니다.

  • src/core/internal/root.js

(6) 빌드

터미널에서 npm run build 명령어를 입력하면 static 폴더 아래에 컴파일된 자바스크립트 파일들이 생성됩니다.

(7) 실행

Repository

본 게시글에서 사용된 코드는 이곳에서 확인하실 수 있습니다.

Reference

Leave a comment