Rules of Hooks

YEONGHUN KO·2022년 5월 19일
0

REACT JS - BASIC

목록 보기
25/31
post-thumbnail

Rules of Hooks

Instagram clone - Dashboard를 만들다가 알게 된 사실이다.

Dashboard 컴포넌트에 photos state를 두고 아래로 내려주기 위해 photo랑 following을 dashboard에 옮기려고 했다.

그래서 usePhotos, useUser를 useEffect안에다 실행했다.
그때 아래와 같은 에러가 생겼다.

  • Uncaught Error: Should have a queue. This is likely a bug in React. Please file an issue.
  • React has detected a change in the order of Hooks called by Dashboard. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks

rules of Hooks 에도 잘 설명되어있지만 hook을 사용하는 순서가 항상 일정해야한다. (또다른 규칙은 hook이 컴포넌트 함수에서 최상위 위치에 사용되는게 낫다.)

Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns.

By following this rule, you ensure that Hooks are called in the same order each time a component renders. T
hat’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls.

그렇다 컴포넌트 가장 최상단에 선언되어야 하며 그래야 hooks의 실행 순서가 일정해진다.

예를 들어 아래와 같은 순서로 hook이 실행된다고 해보자.

function Form() {
  // 1. Use the name state variable
  const [name, setName] = useState('Mary');

  // 2. Use an effect for persisting the form
  useEffect(function persistForm() {
    localStorage.setItem('formData', name);
  });

  // 3. Use the surname state variable
  const [surname, setSurname] = useState('Poppins');

  // 4. Use an effect for updating the title
  useEffect(function updateTitle() {
    document.title = name + ' ' + surname;
  });

  // ...
}

그럼 hook의 실행순서는 아래와 같다.

// First render
// ------------
useState('Mary'); // 1. Initialize the name state variable with 'Mary'
useEffect(persistForm); // 2. Add an effect for persisting the form
useState('Poppins'); // 3. Initialize the surname state variable with 'Poppins'
useEffect(updateTitle); // 4. Add an effect for updating the title

// -------------
// Second render
// -------------
useState('Mary'); // 1. Read the name state variable (argument is ignored)
useEffect(persistForm); // 2. Replace the effect for persisting the form
useState('Poppins'); // 3. Read the surname state variable (argument is ignored)
useEffect(updateTitle); // 4. Replace the effect for updating the title

그러나 두번째 hook(useEffect)를 조건문안에 넣는 다고 해보자

// 🔴 We're breaking the first rule by using a Hook in a condition
if (name !== '') {
  useEffect(function persistForm() {
    localStorage.setItem('formData', name);
  });
}

그럼 순서는 아래와 같이 바뀐다.

useState('Mary'); // 1. Read the name state variable (argument is ignored)
// useEffect(persistForm)  // 🔴 This Hook was skipped!
useState('Poppins'); // 🔴 2 (but was 3). Fail to read the surname state variable
useEffect(updateTitle); // 🔴 3 (but was 4). Fail to replace the effect

그래서 조건문 안에 hook을 실행하면 안되고 hook안에서 조건문을 실행하는게 더 좋다. 기억하자 항상 순서는 일정해야한다.

useEffect(function persistForm() {
  // 👍 We're not breaking the first rule anymore
  if (name !== '') {
    localStorage.setItem('formData', name);
  }
});

그래서 Dashboard page안에서 usePhotosuseUser를 같이 사용하려고 하다가 충돌이 생긴거다. 그래서 그냥 useUserProtectedRoute로 옮겨버리니 문제 해결!

profile
'과연 이게 최선일까?' 끊임없이 생각하기

0개의 댓글