React Hook 이란 뭘까? - 1

프론트 깎는 개발자·2022년 12월 26일
2

react hooks

목록 보기
1/5
post-thumbnail

본 포스팅은 'React Hook' 에 대한 시리즈 게시글 중 1번째 게시글로, hook 자체에 대해 중점적으로 다루고 있습니다!

useState(), useEffect(), useRef()...

정말 수도 없이 써 왔지만, 계속 쓰다 보면, 관성에 의해서 그냥 아무 생각 없이 쓰게 되는 것들이다. 🥲

그래도 한 번은 제대로 짚고 넘어가야 우리가 개발자로서 한 단계 더 성장할 수 있고, 정식으로 '나는 React 개발자다' 라고 자신있게 말할 수 있지 않을까 싶다.

단순히

어? useState( )? 그거 그냥 화면에 표시되는 값 바꿔주는 것 아니에요? 😛

보다는

useState()?
결국 state 는 JS 객체이고, 이 객체의 값이 변할 때마다, 컴포넌트가 re-rendering 되게 해 주는 유용한 react hook 중 하나입니다! 그리고 state 가 변하면 반드시 컴포넌트가 rerender 되기 때문에 내부적으로 변수 값만 관리하고 화면에 표출되는 데이터가 변화할 필요가 없을 때는 성능 측면에서 useState 대신 useRef 를 쓰는 것이 좋습니다! 😎

라고 하는 것이 훨씬 React 에 대한 이해도가 깊어 보인다. 사실 이 답변조차도 더욱 더 깊게 들어갈 수 있지만, 이 정도라도 단순히 useState() 를 계속 반복적으로 사용만 해봤다는 인상보다는 더 공부를 해 보았다는 인상을 줄 수 있다.

그런데 우선, Hook 이라는게 뭘까?

우선, hook 은 React 에만 있는 것이 아니다. WordPress, Git 등에도 있다. hook 자체는

기존에 정해진 process 의 흐름 중간에 사용자가 임의로 개입하여 별도의 로직 (즉, 코드) 을 실행시킬 수 있게 해 주는 tool

이다. 즉, 이미 만들어진 프로그램 중간에 나만의 로직을 추가하는 것이다!

이와 관련해서 이 유튜브 영상 에서 매우 직관적으로 JS 코드를 통해 설명해주시고 있는데, 한번 따라해 보자.

우선, 비어있는 JS 파일을 하나 만들고 함수를 하나 만들어 보자.

// index.js

function mainProcess() {
  console.log("메인 프로세스의 1단계 작업이 시작됩니다. ");
  console.log("메인 프로세스의 2단계 작업이 시작됩니다. ");
  console.log("메인 프로세스의 3단계 작업이 시작됩니다. ");
  console.log("메인 프로세스의 4단계 작업이 시작됩니다. ");
  console.log("메인 프로세스의 5단계 작업이 시작됩니다. ");
}

mainProcess();

단순한 로직이다. mainProcess() 함수 안에서는 각 작업의 시작을 알리는 총 5번의 console.log() 가 불린다.

이런 경우에 우리가 이미 만들어진 mainProcess() 함수를 사용은 하는데, 3단계 프로세스 종료 직후, 그리고 4단계 프로세스 시작 직전 시점에 우리가 정한 행동을 했으면 좋겠다고 가정하자. 이를테면 console.log("엄마 나 콘솔나왔어!") 를 3~4 단계 사이에 콘솔에 찍어보고 싶다고 하자. 😃

지금같은 경우야 그냥 mainProcess() 함수에 가서 3번째 와 4번째 console.log() 새로 하나 넣어주면 손쉽게 원하는 결과를 얻을 수 있다.

// index.js

function mainProcess() {
  console.log("메인 프로세스의 1단계 작업이 시작됩니다. ");
  console.log("메인 프로세스의 2단계 작업이 시작됩니다. ");
  console.log("메인 프로세스의 3단계 작업이 시작됩니다. ");
  console.log("엄마 나 콘솔나왔어!"); // 우리가 추가하고 싶은 로직
  console.log("메인 프로세스의 4단계 작업이 시작됩니다. ");
  console.log("메인 프로세스의 5단계 작업이 시작됩니다. ");
}

mainProcess();

그러나 우리는 react, git 등에서 이미 만들어진 방대한 소프트웨어의 로직을 직접 건드릴 엄두는 나지 않을 것이다. 즉, 우리는 이미 라이브러리 개발자들에 의해 만들어진 mainProcess() 라는 함수를 호출만 해서 쓰는데, 이 함수 내부의 어떤 시점에 단 몇 줄의 로직을 추가하려고 하는데 이를 위해서 라이브러리 전체를 헤집는 일은 매우 비효율적일 것이다.

그러니까 실제로 우리는 mainProcess() 라는 함수 자체는 수정이 현실적으로 불가능하다고 보는 가정을 하는 것이다. 라이브러리 개발자들도 이런 어려움을 이해하고 있고, 이 문제를 해결하기 위해 라이브러리 개발자들이 우리가 쓰라고 친절히 제공해주는 것이 바로 hook 이다!

결론부터 말하자면 mainProcess() 를 호출하며, 함수의 '인자' 로 함수를 넘겨주는 것이다! mainProcess() 의 설계자는 이 함수의 어느어느 시점에 사용자가 원하는 로직을 끼워넣을 수 있다고 미리 설명을 (문서화 등) 해 둘 것이다!

이게 도대체 무슨 말일까? 아래 코드를 보자

// index.js

function mainProcess(hook) {
  console.log("메인 프로세스의 1단계 작업이 시작됩니다. ");
  console.log("메인 프로세스의 2단계 작업이 시작됩니다. ");
  console.log("메인 프로세스의 3단계 작업이 시작됩니다. ");
  hook();
  console.log("메인 프로세스의 4단계 작업이 시작됩니다. ");
  console.log("메인 프로세스의 5단계 작업이 시작됩니다. ");
}

mainProcess(() => {
  console.log("엄마 나 콘솔나왔어!");
});

callback 함수를 이용하여, mainProcess() 를 호출할 때에 3 → 4단계 사이에 호출하고 싶은 함수를 넣을 수 있도록 변경하였다! 결국 이것이 바로 hook 의 핵심 아이디어이다.

기존의 로직 사이에 어떠한 사용자 정의 로직을 추가로 넣고 싶을 때 사용한다

그런데 위의 구현은 아직 완벽하지는 못하다. 지금 우리는 3 → 4단계에서 무언가를 하고 싶었지만, 이 mainProcess() 를 사용하는 또 다른 사용자 (개발자) 들은 1 → 2단계, 2 → 3단계 등의 서로 다른 단계에서 주입하고 싶은 로직이 있을 것이다. 즉, 각 단계마다 주입하고 싶은 로직이 "있다면" 주입할 수 있도록 해 주는 것이다. 이것은 오롯히 라이브러리 제작자의 몫이다. (귀찮으면 안 뚫어도 된다)

하지만 친절한 라이브러리 개발자는 이 라이브러리 사용자들이 주입을 원할 만한 곳에 본인이 원하는 로직을 주입할 수 있도록, 즉, 적재적소에 hook 을 걸 수 있도록 해 줄 것이다 🙂

아래의 코드를 보자.

// index.js

function mainProcess(hooks) {
  typeof hooks.one === "function" ? hooks.one() : null;
  console.log("메인 프로세스의 1단계 작업이 시작됩니다. ");
  
  typeof hooks.two === "function" ? hooks.two() : null;
  console.log("메인 프로세스의 2단계 작업이 시작됩니다. ");
  
  typeof hooks.three === "function" ? hooks.three() : null;
  console.log("메인 프로세스의 3단계 작업이 시작됩니다. ");
  
  typeof hooks.four === "function" ? hooks.four() : null;
  console.log("메인 프로세스의 4단계 작업이 시작됩니다. ");
  
  typeof hooks.five === "function" ? hooks.five() : null;
  console.log("메인 프로세스의 5단계 작업이 시작됩니다. ");
}

mainProcess({
  one: () => {
    console.log("1단계 전에 주입할 작업입니다. ");
  },
  four: () => console.log("엄마 나 콘솔나왔어!"),
});

코드가 다소 복잡해졌지만, 핵심은 각 단계별로 원하는 로직을 주입할 수 있게 되었다는 것이다! 이제는 mainProcess() 를 호출할 때 하나의 객체를 넘기며, 각 객체는 one ~ five 각각에 원하는 로직들을 넣을 수 있다 (없다면 넣지 않아도 되는데, 그 이유는 삼항연산자로 null check 를 해 주었기 때문이다!)

(즉, 삼항연산자를 통해 type 체크를 해 준 이유가, 인자로 넘겨지는 값이 주어지지 않았거나, 주어졌더라고 function type 이 아니라서 () 를 붙여 call 할 수 없는 항목일 수 있는 가능성을 배제시키는, 일종의 error handling 작업이다)

그러면 이제는 mainProcess() 의 함수를 조금도 건드리지 않고, 각 프로세스 사이사이에 우리가 원하는 로직을 집어넣을 수 있게 되었다!

이것이 hook 의 핵심이다. 정말 마지막으로 결론을 내자면

기존의 정해진 프로세스 사이사이에 사용자가 원하는 임의의 로직을 주입할 수 있게 해 주는 tool!

자, 그러면 React hook 은?

hook 의 특성에 대해 알아봤으니, 이제 react hook 에 대해 알아볼 차례이다!

이를 이해하려면, React Component Lifecycle, 즉, 컴포넌트 생애주기 라고 불리는 것에 대한 이해가 선행되어야 한다. 이는 또 다른 topic 으로 다룰 만큼 방대하다...
이미지 출처: https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

간단히 말하자면 React 에서는 Component 가 최초에 화면에 rendering (MOUNTING) 되고, state 등이 변함에 따라 re-rendering (UPDATING) 되고, 더 이상 화면에 표출될 필요가 없어지면 UNMOUNT 되면서 생애주기가 끝이 난다. 사람이 태어나서 성장하고 사망하는 생애주기와도 비슷해서 lifecycle 이라는 명칭이 붙게 되었다.

즉, 기본적으로 각각의 시점 (mount, update, unmount 등) 직전 또는 직후에 어떠한 별도의 로직을 추가할 수 있게 해 주는 것이다!

현재 React 18 기준으로 총 15개의 built-in hook 이 있다! 이들에 대해 앞으로 앞으로의 포스트에서 하나하나 알아보자!

다음 포스팅에서는 React 의 생애주기에 대해 알아보고, 실제 react hook 들에 대해 알아볼 예정이다!

참고자료


AM Coder - What are hooks in programming? (Hooks in Wordpress, React, ElderJS, etc.) - https://youtu.be/tgmvleK5vZI

profile
Comfort Zone 에서 벗어나자!

1개의 댓글

comment-user-thumbnail
2023년 1월 1일

스터디 할 때 React Hook 너무 어려워서 https://sangcho.tistory.com/entry/ReactHooks%EC%9D%98%EB%B9%99%EC%82%B0 요런거 찾아봤던 기억이 나는데 지금은 리액트랑 관련 없는 사람이 되어버렸네요 ㅎㅎ 시리즈 정독하면서 복습 좀 해보겠습니다..!

답글 달기