Hooks

date
Feb 13, 2023
slug
react-hooks
author
status
Public
tags
React
summary
type
Post
thumbnail
category
updatedAt
Jan 15, 2024 12:34 PM

Hook?

React의 Hook은 React 함수형 컴포넌트에서 상태(state)와 라이프사이클 메소드(lifecycle methods)를 사용할 수 있도록 하는 기능입니다. Hook은 기존의 클래스 컴포넌트에서만 사용할 수 있었던 기능들을 함수형 컴포넌트에서도 사용할 수 있게 해주며, 함수형 컴포넌트를 보다 간결하고 유지보수가 쉽도록 만들어 줍니다.

Hook 규칙

  • 컴포넌트의 최상위 레벨에서만 호출해야합니다.
  • 반복문이나 조건문 혹은 중첩 함수 내에서 Hook을 호출하면 안됩니다. -> 리액트 훅은 호출 순서에 의존하기 때문에 조건문이나 반복문 내부에서 실행할 경우 해당 부분을 건너뛰는 일이 발생하는 등의 버그가 발생할 수 있습니다.
  • 리액트 함수 내부에서만 호출해야합니다.

useState

React에는 다양한 Hook이 있지만, 가장 기본적인 것은 useState Hook입니다. useState는 함수형 컴포넌트에서 상태를 관리하는 데 사용되는 훅입니다. useState 훅은 배열을 반환하며, 첫 번째 요소는 현재 상태 값이고, 두 번째 요소는 상태 값을 변경하는 함수입니다.
예를 들어, 다음과 같은 코드를 작성할 수 있습니다.
import React, { useState } from 'react'; function Example() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
위 코드에서 useState 훅은 count 변수와 setCount 함수를 생성합니다. count 변수는 초기값으로 0을 가지고 있으며, setCount 함수는 count 변수를 업데이트합니다. setCount 함수는 새로운 값을 전달받아 해당 값으로 count 변수를 업데이트합니다.
useState 훅을 사용하면, 함수형 컴포넌트에서 상태 값을 관리할 수 있습니다. 이를 통해, 컴포넌트가 렌더링될 때마다 새로운 상태 값을 생성하고 관리할 수 있습니다. 또한, 상태 값을 업데이트하는 방식도 간단하고 직관적입니다.
이 쌍의 이름은 const [something, setSomething] 과 같이 지정하는 것이 일반적입니다.

React는 어떤 state를 반환할지 어떻게 알 수 있을까요?

useState에 전달되는 “식별자”가 없는데 어떤 state 변수를 반환할지 어떻게 알 수 있을까요? 내부적으로 React는 모든 컴포넌트에 대해 한 쌍의 state 배열을 가집니다. 또한 렌더링 전에 0 으로 설정된 현재 쌍 인덱스를 유지합니다. useState 를 호출할 때마다 React는 다음 state 쌍을 제공하고 인덱스를 증가시킵니다. 이 메커니즘에 대한 자세한 내용은 React Hook: 마법이 아니라 배열일 뿐입니다 에서 확인할 수 있습니다.

useState 자세히 뜯어보기

  1. useState같은 Hook들은 react 모듈 안에 선언된 함수입니다.
  1. useState는 실행될 때마다 dispatcher를 선언하고 useState 메서드를 실행해서 그 값을 반환합니다.
  1. 선언한 dispatcher코드를 살펴보면 전역 변수 ReactCurrentDispatcher로부터 dispatcher를 가져옴을 확인할 수 있습니다.
함수가 선언부(dispatcher)보다 상위에 있는 값(ReactCurrentDispatcher)에 접근하고 있습니다.
여기서, Closure의 개념이 등장하게 됩니다.
notion image
👆 useState는 _value 라는 전역에 선언된 변수를 참조하고 있습니다. 이것이 바로 우리가 관리하는 ‘state'에 해당합니다.
자신이 선언된 위치에서 접근할 수 있는 _value 상태를 변경하는 것입니다.
if(_value === undefined) _value = initialValue;
👆 최초 호출에만 초기값을 할당하고 이후에는 initialValue가 아예 사용되지 않습니다.
동작 과정을 흝어보자면...
  1. 처음 컴포넌트 함수가 실행되어 useState를 실행합니다. 👉 _value가 undefined이니 initialValue를 할당합니다.
  1. 다시 컴포넌트 함수가 실행되면 useState가 실행됩니다. 👉 이 때에는_value가 undefined가 아닙니다.
  1. useState가 반환한 값을 변수에 할당합니다.
  1. setState함수는 자신과 함께 반환된 변수를 변경시키는 것이 아니라 다음 useState가 반환할 react 모듈의 _value를 변경시키고 컴포넌트를 리렌더링 시키는(트리거) 역할을 합니다.
변경된 값은 다음 컴포넌트 함수가 실행될 때 useState가 가져오기 때문에 setState 호출 이후 로직에서도 state의 값은 이전과 동일합니다.

다음 렌더링 전에 동일한 state 변수를 여러 번 업데이트하기

흔한 사례는 아니지만, 다음 렌더링 전에 동일한 state 변수를 여러 번 업데이트 하고 싶다면 setNumber(number + 1)와 같은 _다음 state 값_을 전달하는 대신, setNumber(n => n + 1) 와 같이 큐의 이전 state를 기반으로 다음 state를 계산하는 _함수_를 전달할 수 있습니다. 이는 단순히 state 값을 대체하는 것이 아니라 React에게 “state 값으로 무언가를 하라”고 지시하는 방법입니다.
import { useState } from 'react'; export default function Counter() { const [number, setNumber] = useState(0); return ( <> <h1>{number}</h1> <button onClick={() => { setNumber(n => n + 1); setNumber(n => n + 1); setNumber(n => n + 1); }}>+3</button> </> ) }

updator function 사용하기

여기서 n => n + 1업데이터 함수(updater function) 라고 부릅니다. 이를 state 설정자 함수에 전달 할 때
  1. React는 이벤트 핸들러의 다른 코드가 모두 실행된 후에 이 함수가 처리되도록 큐에 넣습니다.
  1. 다음 렌더링 중에 React는 큐를 순회하여 최종 업데이트된 state를 제공합니다.
업데이터 함수 인수의 이름은 해당 state 변수의 첫 글자로 지정하는 것이 일반적입니다.
setEnabled(e => !e); setLastName(ln => ln.reverse()); setFriendCount(fc => fc * 2);