Studying/React

리액트 공부하기 - hooks를 최상단에 작성 해야 하는 이유? 변수에 담아서 사용하는 이유?

creamymood 2025. 5. 22. 20:35

훅이란?

아래 블로그에서 자세히 읽어볼 수 있다.

 

리액트 공부하기 - custom hooks? 그냥 함수 차이?

custom hooks를 공부하며 헷갈리게 된 또 기본 개념- 다시 짚고 갑시다.우선 훅(hook)이 뭘까. 리액트(React)에서 **훅(Hook)**은 함수형 컴포넌트에서 **상태(state)**나 라이프사이클(lifecycle) 같은 리액트

creamymood.tistory.com


결론:

더보기

React는 훅 호출 순서에 따라 상태를 기억해요. 만약 훅 호출이 조건이나 반복문 안에서 바뀌면, React가 어떤 훅이 어느 상태인지 헷갈려서 오류가 생길 수 있기 때문에 함부로 쓰지 못하니까  “리턴 값을 이용한다”

  • 훅은 함수이지만, 훅을 호출해서 리턴받은 값(함수나 상태 변수 등)을 변수에 저장해서 나중에 사용하는 거예요.
  • 예를 들어 useNavigate() 훅은 페이지 이동을 도와주는 함수(navigate)를 반환해요.
  • 그걸 변수에 저장해서, 이벤트 핸들러 같은 나중에 실행되는 함수 안에서 호출해 페이지를 이동하는 거죠.

간단히 말하면

  1. 훅은 렌더링 중 최상단에서 딱 한 번 호출해서
  2. 필요한 값을 리턴 받고, 변수에 저장한 뒤
  3. 그 변수를 이벤트나 다른 함수에서 필요할 때 호출해서 사용한다

훅도 함수긴 함수다. 하지만,

먼저 1. 훅은 단순한 함수가 아니다

 useState, useEffect, useNavigate 같은 훅도 겉보기엔 그냥 함수처럼 생겼어.

하지만 React가 컴포넌트를 렌더링하면서 내부적으로 ‘상태 관리 시스템’과 연결된 특별한 함수야.

(뭔가 바뀔 수 있는 것들.. 상태에 관한것들 ? 뭔가 동적인 ?? 이런 뉘앙스의 함수일까나?)

 

그래서 얘들은:

  • 그냥 호출되는 게 아니라,
  • “언제, 어디서, 몇 번째로” 호출되는지가 아주 중요해!

훅은 호출되는 위치(컴포넌트 렌더링 과정)에서 내부 상태나 컨텍스트를 관리하기 위해 만들어졌기 때문이야.

더보기

리액트 훅은 단순한 함수가 아닌,

상태나 외부의 시스템이랑 연결된 그러한 함수이다.


1. 함수의 반환값이란?

함수는 어떤 일을 수행하고, 그 결과값을 밖으로 내보낼 수 있어. 이걸 반환값이라고 해.

예를 들어:

function add(a, b) {
  return a + b; // a + b의 결과를 반환
}

const result = add(2, 3); // 5가 result에 저장됨
  • add 함수는 숫자 두 개를 더해서 결과를 반환하고,
  • 이 반환값을 result라는 변수에 저장해서 나중에 쓸 수 있어.

2. React 훅(Hook)은 뭘 반환할까?

React 훅도 함수야. 그런데 훅은 특별한 역할을 하기 위해 만들어진 함수이고, 훅마다 반환하는 게 달라.

  • 예를 들어 useState는 상태값과 상태를 바꾸는 함수를 배열 형태로 반환해:
const [count, setCount] = useState(0);
  • 여기서 count는 상태값, setCount는 상태를 바꾸는 함수야.
  • useNavigate()라는 훅은 **"경로를 이동시키는 함수"**를 반환해:
const navigate = useNavigate();
navigate('/home'); // 이렇게 호출해서 경로를 이동시켜

 React는 어떻게 작동할까?

React는 화면(UI)을 렌더링할 때 컴포넌트 함수를 다시 실행해.
이때, 컴포넌트 안에서 useState, useEffect 같은 훅을 차례대로 호출하면서 상태나 기능들을 기억해.

React는 훅을 호출하는 순서와 개수를 기준으로 상태나 로직을 연결해 놓는 구조야.


 

더보기

 예시로 설명해볼게

function MyComponent() {
  const [count, setCount] = useState(0); // 첫 번째 훅
  const [name, setName] = useState('Jane'); // 두 번째 훅

  return <div>{count} - {name}</div>;
}

위 코드에서 React는:

  1. 컴포넌트를 렌더링할 때,
  2. useState(0) → "아, 이건 첫 번째 상태"
  3. useState('Jane') → "이건 두 번째 상태"
    이런 식으로 기억해놔.

그런데 이런 식이면 어떻게 될까?

function MyComponent() {
  if (someCondition) {
    const [count, setCount] = useState(0); // 조건에 따라 호출됨
  }

  const [name, setName] = useState('Jane');

  return <div>Hi</div>;
}
  • 만약 someCondition이 true일 때만 useState(0)이 실행되면,
  • 어떤 렌더링에서는 useState('Jane')가 첫 번째 훅이 되고,
  • 어떤 렌더링에서는 두 번째 훅이 되겠지?

 그러면 React는 "어? 이게 예전에 첫 번째였는데 지금은 두 번째야? 뭐가 바뀐 거지?"
 내부에서 상태를 헷갈리게 돼. 그래서 에러가 나는 거야.


 그래서 규칙이 생긴 거야!

"훅은 항상 컴포넌트 최상단에서, 조건 없이 호출해야 한다."

이런 규칙을 지키면 React는 훅의 순서를 항상 동일하게 추적할 수 있어.



1. 왜 일반 함수나 조건문, 이벤트 핸들러 안에서는 훅을 못 쓰는가?

핵심 키워드는:

“React가 훅 호출 순서를 기준으로 상태를 기억하기 때문이다.”

 

 

1-1 왜 조건문에서 사용이 안됌?

더보기

 예시: 이런 식으로 동작함

function MyComponent() {
  const [count, setCount] = useState(0); // 1번째 훅
  const [name, setName] = useState('Jane'); // 2번째 훅
}

React는 이렇게 기억함:

  • 1번째 훅 → count 상태
  • 2번째 훅 → name 상태

근데 만약 이렇게 쓰면?

function MyComponent() {
  if (someCondition) {
    const [count, setCount] = useState(0); // ❌ 어떤 렌더링에서는 호출되고, 어떤 때는 안 됨
  }

  const [name, setName] = useState('Jane'); // 💥 순서 꼬임
}

 그럼 어떻게 되냐면:

  • 어떤 렌더에서는 useState(0)이 호출됨 → count = 1번째
  • 어떤 렌더에서는 안 호출됨 → name이 1번째에 위치함
  • 결과: React는 상태를 잘못 연결하게 되고, 오류 발생!

 1-2 왜 일반 함수나 이벤트 핸들러 안에서는 훅을 쓰면 안 될까?

더보기

useState, useEffect 같은 훅은
→ 컴포넌트 함수가 렌더링될 때 자동으로 호출되는 구조야.

근데 일반 함수나 이벤트 핸들러는
→ 렌더링 도중이 아니라, 나중에 어떤 “행동”이 생겼을 때 실행되는 코드야.

React의 “렌더링-상태 동기화 시스템”과 맞지 않음

React는:

  • 컴포넌트 렌더 → 훅 호출 순서 기억 → 상태 저장
  • 다음 렌더 시에도 똑같은 순서로 훅 호출해야 상태 유지 가능

근데 이벤트 핸들러는

  • 렌더링이랑 관계 없는 “그냥 실행되는 함수”라서
  • 호출 순서가 바뀔 수 있음
  • 심지어 렌더링 중이 아닐 수도 있음

➡️ 이런 곳에 훅을 넣으면 React는 “얘를 추적할 수도, 저장할 수도” 없어!

 

 


2. 왜 useNavigate 같은 훅은 변수에 꼭 담아서 써야 해? (가독성 이유 빼고)

질문에서 말한 이 코드:

useNavigate()('/home'); // 이거 왜 안 돼?

사실 동작은 해. 에러는 안 나.
하지만 그렇게 쓰면 안 되는 이유가 있어.


⚠️ 이유 1: 렌더링 타이밍 때문에 위험함

useNavigate()('/home');

이건 컴포넌트가 렌더링될 때마다 실행됨.
즉, 페이지 로딩할 때마다 강제 이동함. → 💥 무한 루프 가능

그래서 이렇게 써야 해:

const navigate = useNavigate(); // 훅 → 변수에 저장 (렌더링 중에만 호출됨)

그리고 나서:

const handleClick = () => {
  navigate('/home'); // 이벤트 발생 시에만 실행됨!
};

✔️ 이렇게 하면 렌더링 중에는 훅만 호출되고, 이동은 버튼 누를 때 실행됨.
→ 안전하고 의도한 대로 동작해.


🔍 이유 2: 디버깅/재사용이 쉬움

const navigate = useNavigate();
  • navigate 함수는 나중에 여러 곳에서 쓸 수 있어
  • 예: useEffect, 이벤트 핸들러 등등

결론 ->

훅은 위와 같은 내용들로 직접 사용하면 안되고 반환 함수를 사용하는거니까,, 

아 useNavigate라는 훅이 navigate라는 함수를 반환하는 것!

navigate 함수를 사용해야 한다..

 

익숙한 [num, setNum] = useState(null)

 

이 때, setNum을 쓰는 것 처럼...


🔧 useNavigate()란?

  • React Router에서 페이지 이동(네비게이션)을 프로그래밍적으로 할 수 있도록 도와주는 함수예요.
  • useNavigate()를 컴포넌트 안에서 호출하면, navigate라는 함수를 반환해요. 그 함수를 사용하면 원하는 페이지로 이동할 수 있어요.

비유로써 이해해보기

더보기

🎛️ 리모컨(일반 함수) 안에 시스템 버튼(훅)을 넣을 수 없는 이유는?

리모컨은 기계를 작동시키는 수단이에요.
그런데 리모컨 안에 시스템 내부 버튼이 들어있으면...

  1. 리모컨이 눌릴 때마다
  2. 시스템 내부에 새로운 버튼이 생기거나 위치가 바뀌게 돼요.

💥 이건 시스템 입장에서는 "어? 이 버튼은 원래 여기에 없었는데??" 라는 상황이에요.
그래서 React가 훅의 순서를 추적하지 못하고 오류가 나는 거죠.


 쉽게 정리하면:

  • 훅은 렌더링 시점에, 정해진 위치에서만 한 번씩 실행되어야 해요.
  • 일반 함수나 이벤트 핸들러 안에서 훅을 넣으면,
    React 입장에선 "렌더링 도중이 아닌 시점"에 훅이 새로 생긴 것처럼 보이기 때문에 오류가 나요.

예시로 비교해볼게요:

✅ 올바른 코드

function MyComponent() {
  const [num, setNum] = useState(0);  // 시스템 버튼: 여기에 고정

  const handleClick = () => {
    setNum(num + 1);  // 리모컨 버튼: 기존 시스템 버튼의 결과 사용
  };

  return <button onClick={handleClick}>증가</button>;
}

❌ 잘못된 코드

function MyComponent() {
  const handleClick = () => {
    const [num, setNum] = useState(0); // ❌ 리모컨 안에 시스템 버튼! 오류 발생
  };

  return <button onClick={handleClick}>증가</button>;
}

 

그냥 내가 이해한 건 이거다.

훅이 약간 상태나 그런 시스템이랑 관련된 특수한 함수니까..

시스템이 자동으로 실행시키는 이러한 특수 버튼을, 일반 버튼 안에 넣어버리면 작동이 안되는거지..

 

안에 넣으면 오류가 나니까, 최상단에 적는다. 

 

  1. 훅은 렌더링 중 최상단에서 딱 한 번 호출해서
  2. 필요한 값을 리턴 받고, 변수에 저장한 뒤
  3. 그 변수를 이벤트나 다른 함수에서 필요할 때 호출해서 사용한다