비동기함수 완료와 컴포넌트 렌더링 시점

hyeryeon·2024년 7월 3일

로그인하고 네비게이션 바 버튼을 통해 board 페이지로 오면

로그인상태이기때문에 좋아요가 활성화가 되어야하는데 ⇒ 여전히 비활성화

새로고침을 하면 활성화가 된다....

의존성배열을 로컬스토리지로 해서 로그인되면 useEffect되게- 실패
context API로 로그인상태를 전달 -실패
navigation 바에서 네비게이트 후 window.location.reload() - 실패

useEffect(() => {
fetchLikedPosts();
fetchTotalRecipes();

}, [location.pathname,accessToken]);

될것 같은..되야만 하는 코드에서 안되고있다..무슨문제인지ㅠㅠ

그래서 클린코드 스터디에서
"로그인처리 시 많이 사용되는 window.location.reload()는 페이지 전체를 새로고침하는거라 성능에 좋지못하다 지양하자" 했던 것이 생각났고,

로그인처리시 window.location.reload()를 사용해본적이 없었다.
내 문제에서는 새로고침하면 좋아요가 활성화되기때문에 '문제해결'에서만은 딱 좋다고 생각했다.

useEffect(() => {
fetchLikedPosts();
fetchTotalRecipes();

}, [location.pathname,accessToken]);

기존 사용했던 코드에서는 의존성배열에
[location.pathname,accessToken]가 있는데

  • location.pathname: 페이지의 경로가 변경될 때마다(예: 네비게이션 바를 통해 다른 페이지로 이동할 때) 해당 함수들을 호출하여 최신 데이터를 가져옵니다
  • accessToken: 사용자의 로그인 상태가 변경될 때마다(accessToken이 업데이트될 때) 최신 데이터를 가져옵니다.

근데 페이지 경로 변경에는 location.pathname 인데 왜 이것만으로는 안되는가/??

location.pathname으로만 리렌더링을 트리거했을 때 문제가 발생한 이유는,

  • location.pathname이 업데이트된 후 컴포넌트가 마운트되면서 fetchLikedPostsfetchTotalRecipes를 호출하지만, 이것은 RecipeCard 컴포넌트가 이미 렌더링된 후에 상태가 변경되기 때문에 좋아요 상태가 초기화되지 않는다.
    • RecipeCard 컴포넌트 렌더링 -> fetchLikedPostsfetchTotalRecipes
      (비동기 데이터 로딩의 순서 문제: fetchLikedPosts와 fetchTotalRecipes가 완료되기 전에 컴포넌트가 렌더링. -> 좋아요 상태가 아직 업데이트되지 않은 상태로 컴포넌트가 렌더링)

-> 특히, RecipeCard 컴포넌트가 Board 컴포넌트의 상태 변경을 감지하고 이를 반영하는 방식에 있어, 비동기적으로 데이터가 로드되면서 생기는 시차로 인해 좋아요 상태가 일관되지 않게 보일 수 있다.

해결하기 위해 페이지가 로드될 때마다 강제 새로고침을 수행하도록 하여, 컴포넌트가 마운트될 때 모든 상태가 최신 상태로 로드되도록 하였다.

 useEffect(() => {
    fetchLikedPosts();
    fetchTotalRecipes();
    ☄️if (!window.location.hash) {
      window.location = window.location + '#loaded';
      window.location.reload();
    }
  }, [location.pathname,accessToken]);
  • if (!window.location.hash): 현재 URL에 해시(#loaded)가 없는지 확인. => 페이지가 처음 로드될 때 또는 해시가 없는 상태일 때 실행

  • window.location = window.location + '#loaded': 현재 URL에 #loaded 해시를 추가합니다. 이는 페이지가 새로고침되었음을 나타내기 위한 것입니다.

  • window.location.reload(): 페이지를 새로고침합니다. 이는 데이터를 새로고침하여 최신 상태로 유지하기 위해 사용됩니다.

    해시를 사용한 페이지 새로고침의 장점
    -상태 유지: 새로고침 후에도 페이지 상태를 유지할 수 있습니다.
    -히스토리 관리: 브라우저 히스토리 스택을 통해 뒤로 가기 버튼으로 이전 상태로 쉽게 복귀할 수 있습니다.
    -SEO와 캐싱: 검색 엔진 최적화와 브라우저 캐싱에 긍정적인 영향을 미칩니다.
    -클라이언트 사이드 라우팅: 단일 페이지 애플리케이션에서 부드러운 사용자 경험을 제공합니다.


추가

새로고침 없이 useEffect 훅으로 상태를 업데이트할 때는

비동기 상태 업데이트 타이밍: fetchLikedPosts와 fetchTotalRecipes가 비동기적으로 실행되면서 컴포넌트가 렌더링되는 시점에 좋아요 상태가 아직 설정되지 않을 수 있다


이를 해결하기 위해서는 likedPosts 상태가 업데이트된 직후에 => RecipeCard 컴포넌트를 다시 렌더링하도록 보장해야 합

추가 해결방법

해결 방법
보다 나은 해결 방법은 상태 관리와 로딩 상태를 도입하여 비동기 데이터 로딩과 컴포넌트 렌더링 간의 타이밍 문제를 해결하는 것입니다. 예를 들어:

const [loading, setLoading] = useState(true); // 로딩 상태 추가

useEffect(() => {
  const fetchData = async () => {
    setLoading(true); // 로딩 시작
    await fetchLikedPosts();
    await fetchTotalRecipes();
    setLoading(false); // 로딩 완료
  };
  fetchData();
}, [location.pathname, accessToken]);

return (
  <main className="Board pb-24">
    {loading ? (
      <div>Loading...</div> // 로딩 상태일 때 표시할 내용
    ) : (
      <>
        {/* 컴포넌트 렌더링 */}
      </>
    )}
  </main>
);

이 접근 방식은 비동기 함수가 완료된 후에만 컴포넌트가 렌더링되도록 하여, 좋아요 상태와 같은 데이터를 정확히 반영할 수 있게 합니다.

0개의 댓글