한입 패치노트) React Router v7 업데이트 관련 강의 변경사항 안내

안녕하세요 한입 리액트 수강생 여러분 이정환입니다.

이 안내는 우리 강의의 12섹션을 수강중이시거나 또는
이미 수강을 완료하신 분들을 대상으로 작성되었음을 먼저 알려드립니다.


2024년 11월 22일 React Router의 새로운 버전 v7이 출시 되었습니다.

이로 인해 우리 강의의 12 섹션에서 구현하는 "감정 일기장"의 구현 사항에 일부 변화가 생겨 안내드립니다.

 

강의 변경 사항

  • 12.15) Edit 페이지 구현하기 의 28분 51초 ~ 종료 까지의 내용이 수정되었습니다.

어떤 문제가 있었는지?

React Router v7의 업데이트로 useNavigate Hook을 호출해 반환받을 수 있었던 navigate 함수가 이제 비동기적으로 작동하도록 변경되었습니다.

const nav = useNavigate();
// 이제 이 함수는 비동기적으로 동작합니다.
// 마우스 커서 올려보면 Promise 타입으로 나와요!

 

이런 변경점으로 인해 감정 일기장 프로젝트에서 특정 일기를 삭제할 때,
다음 그림과 같이 "존재하지 않는 일기입니다" 라는 Alert가 발생하는 버그가 발생하게 되었습니다.

image.png

 

이 버그가 발생한 이유는 바로! 페이지 이동이 요청된 이후에도 React Hook가 실행되기 때문입니다.

구체적으로 설명하자면, 감정 일기장 프로젝트의 Edit(수정) 페이지 컴포넌트에는 다음과 같이 "삭제하기" 버튼을 클릭할 때 실행할 onClickDelete 함수가 선언되어 있습니다.

// src/pages/Edit.jsx

const Edit = () => {
  // ... 중략
  const curDiaryItem = useDiary(params.id);

  const onClickDelete = () => {
    if (
      window.confirm("일기를 정말 삭제할까요? 다시 복구되지 않아요!")
    ) {
      // 일기 삭제 로직
      onDelete(params.id);
      nav("/", { replace: true });
    }
  };
  // ... 중략
};

따라서 사용자가 "일기 삭제" 버튼을 클릭하면 위 Edit 컴포넌트의 onClickDelete 함수가 실행되어 정말 일기를 삭제할 것인지 다시 한번 묻는 경고창이 발생하고 이 경고창에 "확인"을 클릭하면 다음의 동작이 실행됩니다.

  • onDelete 함수를 호출해 현재 페이지에서 조회중인 일기 데이터를 State로 부터 삭제하도록 요청합니다.

  • navigate 함수를 호출해 인덱스 페이지로 이동합니다.

이때 기존의 React Router v6 버전까지는 onDelete 함수는 비동기적으로, navigate 함수는 동기적으로 동작하기 때문에 navigate 함수가 호출되자마자 Edit 컴포넌트가 언마운트 되었습니다.

컴포넌트가 언마운트 되면 해당 컴포넌트의 useEffect 등의 모든 React Hooks는 작동을 멈춥니다. 그러므로 Edit 컴포넌트에서 현재 일기 데이터를 불러오기 위해 사용한 useDiary Hook의 useEffect가 또한 다시 호출되지 않았습니다.

// src/hooks/useDiary.js
const useDiary = (id) => {
  //... 중략
  useEffect(() => {
    const currentDiaryItem = data.find((item) => String(item.id) === String(id));

    if (!currentDiaryItem) {
      window.alert("존재하지 않는 일기입니다.");
      nav("/", { replace: true });
    }

    setCurDiaryItem(currentDiaryItem);
  }, [id, data]);
  //... 중략
};

 

그러나 이번에 업데이트 된 React Router v7 버전부터는 navigate 함수가 비동기적으로 동작합니다. 그렇기에 navigate 함수를 호출한다고 기존 페이지 컴포넌트가 즉시 언마운트 되지 않습니다.

따라서 이로 인해 일기 State의 변화가 발생하고 나서 위 useDiary Hook의 useEffect가 다시 호출되는 현상이 발생하게 되었습니다.

그런데 일기의 삭제가 완료된 이 시점에는 useEffect에서 불러오는 현재 일기 데이터인 currentDiaryItem의 값이 존재하지 않기 때문에 조건문에 의해 "존재하지 않는 일기입니다" 라는 경고창이 발생하게 됩니다.

이해를 돕기 위해 순서대로 정리하자면 다음과 같이 동작하는 것 입니다.

  • 사용자가 "삭제 하기" 버튼 클릭

  • (비동기) onDelete 함수 호출

  • (비동기) navigate 함수 호출

  • onDelete 함수 완료 -> data State값 변화 -> useEffect 실행 -> "존재하지 않는 .." 경고창 발생

  • 페이지 이동

결과적으로 이런 변경점으로 인해 "삭제 하기" 버튼 클릭시 불필요한 경고창이 발생하게 되어 의도하지 않은 방향으로 앱이 동작하게 됩니다.

 

문제 해결 방법

이 문제를 해결하는 방법은 간단합니다. useDiary Hook의 useEffect가 일기 삭제 등의 State 수정 이후에는 호출되지 않도록 다음과 같이 의존성 배열을 수정하면 됩니다.

// src/hooks/useDiary.js
const useDiary = (id) => {
  //... 중략
  useEffect(() => {
    const currentDiaryItem = data.find((item) => String(item.id) === String(id));

    if (!currentDiaryItem) {
      window.alert("존재하지 않는 일기입니다.");
      nav("/", { replace: true });
    }

    setCurDiaryItem(currentDiaryItem);
  }, [id]); // <- 수정된 포인트
  //... 중략
};

[id, data] 에서 [id]로 의존성 배열을 변경하였습니다. 이제 사용자가 "일기 삭제" 버튼을 클릭해 일기 데이터를 보관하는 data State의 값이 변화해도 이 useEffect는 다시 호출되지 않게 됩니다. 이렇게 문제를 간단히 해결할 수 있습니다.

여러분의 실습에 불편함이 없으시도록 위 내용을 강의에 추가해두었으니 궁금하신 분들께서는 직접 확인해보셔도 좋을 것 같습니다 😃


마치는 말씀 & 2024 연말 회고 이벤트

마지막으로 한입 리액트를 선택해 수강해주신 모든 분들께 진심으로 감사하다는 인사를 드립니다.

따뜻하고 포근하게 연말 잘 마무리 하시고 즐거운 새해 맞이하시길 응원하겠습니다.

 

앗! 그리고 현재 한입 개발자 커뮤니티에서 2024년 연말 회고 이벤트를 진행하고 있습니다.

상품으로 스초생 케이크, 스타벅스 3만원 상품권, 배민 3만원 상품권을 나눠드리고 있으니

한번 구경오시면 좋겠습니다 😃

링크 : https://cafe.naver.com/winterlood/189

게시글상단배너.png

 

 

 

채널톡 아이콘