Develop+

리액트 코어 - 훅 만들어보기 본문

React

리액트 코어 - 훅 만들어보기

Sunny Buddy 2022. 11. 14. 02:00
728x90

리액트 16.8v 이후부터 함수형 컴포넌트 내에서 hook을 사용할 수 있다. 

클래스형 컴포넌트에서 라이프사이클을 이용하면서 여러 문제점들을 만났고, 리액트 팀에서는 그를 보완하기 위해 

훅이라는 개념을 도입했다.

 

그렇다면 훅은 어떻게 구현될까?

 

가장 기본적인 훅인 useState에 대해 살펴보자.

useState의 기본적인 문법은 const [variable, variableSetter] = useState(initialValue); 형식으로 

useState의 파라미터로 초기값을 받고, value와 그 값에 유일하게 접근할 수 있는 setter를 반환한다. 

 

export function useState(initValue) {
  let value = initValue;
  return value,
   (nextValue)=>{
     value = nextValue;
  }];
}

가장 기본적인 형태로 만들어본다면 value와 setter를 반환하는 이런 형태의 useState를 구현할 수 있을 거 같다. 

 

여기서 리액트팀은 우리가 상태값을 변경하여 컴포넌트를 리랜더링 했을 때 컴포넌트의 구조, 순서가 항상 같을 것이라고 생각했다. 항상 순서가 같다면 화면을 다시 그리지 않고 상태만을 변경하고자 했고, 현재 컴포턴트의 순서를 기억해 그 안에 hook들을 기억해 접근할 수 있도록 했다. 

 

우리가 사용할 컴포넌트의 순서를 기억할 변수와, 훅들을 저장할 수 있도록 배열을 선언해보겠다. 

let currentComponent = 0;
let hooks = [];

이런식으로 컴포넌트의 순서를 기억할 수 있는 변수와 훅이 선언이 되었다. 

 

위의 useState코드를 순서가 바뀌지 않을 것을 가정한 코드로 바꾸어보자.

export function useState(initValue) {
  const position = currentComponent;
  if(!hooks[position]) {
    hooks[position] = initValue;
  }
  
  return [hooks[position],
   (nextValue)=>{
      hooks[position] = nextValue;
  }];
}

위 코드에서 position이라는 변수에 currentCopoent 의 위치를 캡쳐하고, 

hooks의 변수에 현재 컴포넌트 순서에 값이 있는지를 체크한다. 

해당 순서의 컴포넌트에 값이 없다면, 최초 실행임을 확인하고 초기값을 해당 순서의 hook에 할당한다. 

그리고 현재순서의 hook을 가리키는 hooks[position]과 그 값은 세팅할 수 있는 함수를 리턴해준다. 

 

여기서 컴포넌트들을 하나씩 그리는 react의 createElement 메서드에서 한 컴포넌트를 그릴 때마다 currentCompoent의 순서를 하나씩 증가시켜 준다. 

 

이전 포스트에서 포스팅한 createElement 메서드 코드에 추가 코드를 작성해보겠다. 

export function createElement(tagName, props, ...children) {
  // 클래스와 function와 구분할 방법이 없다. 
  // 그래서 상속받은 function인지를 체크한다. 
  if(typeof tagName === 'function') {
    // 코드에서 Component를 상속받았는지를 체크한다.
    if(tagName.prototype instanceof Component) {
      //클래스를 인스턴스화 한 후
      const instance = new tagName({...props, children});
      // 노드를 뱉는 render 를 실행한다. 
      return instance.render();
    }else {
      currentComponent++;
      return tagName.apply(null, [props, ...children]);

    }
  }
  return {tagName, props, children}
}

함수형 컴포넌트에서만 hook사용이 가능하기 때문에, 우리는 클래스형 컴포넌트인지 확인하는 if 구문 뒤의 else 구문에 현재 컴포넌트 순서를 증가시켜주는 currentComponent++; 코드를 추가했다. 

 

만약 훅을 사용하는 컴포넌트가 조건부로 랜더링 되는 컴포넌트라면, 훅을 기억하는 순서가 뒤죽박죽 섞일 수가 있다. 

이와같은 로직으로 훅이 만들어지기 때문에, 리액트 팀에서는 조건부로 랜더링되는 컴포넌트 내에서는 훅을 사용하지 말라고 설명한다. 

 

이렇게 우리가 사용하는 제일 기본적인 hook인 useState를 구현할 수 있다. 

 

 

Ref - 김민태의 React와 Redux로 구현하는 아키텍처와 리스크관리

728x90