프로젝트 이모저모/HoduMarket 프로젝트

오픈마켓) navbar 렌더링 이슈

Ella Seon 2023. 4. 17. 21:05

0. 버그 현황

- buyer/seller 유저타입에 따라 navbar 가 달라진다.

buyer일 경우에는 왼쪽 그림, seller 일 경우에는 오르쪽 그림으로 렌더링되어야한다.

- buyer로 로그인을 하고 홈 페이지로 이동시 navbar 가 렌더링이 되지않음

- 즉, 로그인을 해서 쿠키에 token 과 userType 이 저장되어있는데,  홈페이지로 이동 즉시 렌더링이 되지 않음. 새로고침을 해야지만 렌더링이 제대로 됨.

- loginSlice.ts 에서 console.log(typeItem) 과 console.log(tokenItem)을 했을 때 undefined로 나옴. 새로고침을 해야지만 데이터가 출력된다.

1. 버그 코드 및 버그 원인

//Cookies.ts

import { Cookies } from "react-cookie";

const cookies = new Cookies();

// 쿠키에 값을 저장할 때
export const setCookie = (name: string, value: string) => {
  return cookies.set(name, value, { maxAge: 60 * 60 * 3, path: "/" });
};

// 쿠키에 있는 값을 꺼낼때
export const getCookie = (name: string) => {
  return cookies.get(name);
};

//쿠키를 지울때
export const removeCookie = (name: string) => {
  return cookies.remove(name);
};
function Navbar() {
  const token = useAppSelector((state: RootState) => state.login.token);
  const userType = useAppSelector((state: RootState) => state.login.userType);
  console.log(userType);

  return (
    <S.HomeHeader>
      <S.Navbar>
        <S.HeaderSearchWrapper>
          <S.Logo src={Logo} alt="호두마켓 로고" />
          <S.SearchBarWrapper>
            <S.SearchInp type="text" placeholder="상품을 검색해보세요!" />
            <S.SearchBtn type="button" aria-label="검색하기 버튼" />
          </S.SearchBarWrapper>
        </S.HeaderSearchWrapper>
        {userType === "BUYER" ? (
          <S.HeaderUserWrapper>
            <Link to="/cart">
              <S.CartBtn type="button" aria-label="장바구니에 담기 버튼">
                <img src={CartIcon} alt="장바구니 아이콘버튼" />
                <S.CartText>장바구니</S.CartText>
              </S.CartBtn>
            </Link>

            <S.UserBtn>
              <img src={UserIcon} alt="유저 아이콘 버튼" />
              <S.UserText>{token ? "마이페이지" : "로그인"}</S.UserText>
            </S.UserBtn>
          </S.HeaderUserWrapper>
        ) : (
          <S.HeaderUserWrapper>
            <S.UserBtn>
              <img src={UserIcon} alt="유저 아이콘 버튼" />
              <S.UserText>마이페이지</S.UserText>
            </S.UserBtn>
            <S.ShoppingBagBtn type="button" size="ms">
              판매자센터
            </S.ShoppingBagBtn>
          </S.HeaderUserWrapper>
        )}
      </S.Navbar>
    </S.HomeHeader>
  );
}

export default Navbar;

- 아래 console.log(typeItem) 과 console.log(tokenItem) 모두..undefined가 나온다.

✅ 왜 undefined가 나올까?

- getCookie() 함수는 쿠키 값을 가져오기 위해 react-cookie 패키지의 Cookies 객체를 생성한다. 이 객체는 브라우저의 document.cookie 속성을 사용하여 쿠키 값을 읽고 쓰는 역할을 한다. 그러나 브라우저에서 쿠키 값을 읽는 것은 document.cookie 속성을 통해 이루어지는데, 이 속성은 브라우저가 새로고침되거나 페이지가 로드될 때만 업데이트된다.

따라서 loginSlice.ts 파일에서 getCookie() 함수를 호출하여 쿠키 값을 가져오는 부분이 모듈이 import 되는 시점에 실행되면, 현재 브라우저의 쿠키 값을 가져올 수 없다.  그래서 undefined가 반환되는 것.

 

✅그런데, 로그인 버튼을 누르면 useNavigate('/') 로 이동하는데, 페이지가 새로고침 되는거 아닌가?

React Router의 useNavigate() hook을 사용하면 페이지를 새로고침하지 않고도 다른 URL로 이동할 수 있다. 이 hook은 history 객체를 사용하여 브라우저의 URL을 업데이트 한다.
React Router는 브라우저의 pushState() API를 사용하여 URL을 변경한다. pushState() API는 브라우저의 URL을 업데이트하지만, 페이지를 새로고침하지는 않는다. 대신, 브라우저의 주소 표시줄에 새로운 URL이 나타나고, 이전 URL로 돌아갈 수 있는 뒤로 가기 버튼이 활성화 된다.
따라서 useNavigate() hook을 사용하여 다른 URL로 이동할 때, 브라우저가 새로고침되지 않고도 URL이 변경되며, 해당 URL에 대한 컴포넌트가 렌더링된다.

2. 해결 코드

- 해결하기 위해서는 렌더링 시점이 아니라, fetchLogin() 함수에서 API 호출이 성공하여 반환된 토큰과 유저 타입 값을 쿠키에 저장할 때, 해당 값을 Redux state에도 저장해주어야 한다.

//loginSlice.ts

export const fetchLogin = createAsyncThunk(
  "login/fetchLogin",
  async (
    { username, password, login_type }: LoginData,
    { rejectWithValue }
  ) => {
    try {
      const data = { username, password, login_type };
      const response = await axios.post(`${BASE_URL}/accounts/login/`, data);
      console.log(response.data);

      if (response.data) {
        setCookie("token", response.data.token);
        setCookie("userType", response.data.user_type);
      }
      return {
        token: response.data.token,
        userType: response.data.user_type,
      };
    } catch (error: any) {
      console.log(error.response.data);
      return rejectWithValue(error.response.data.FAIL_Message);
    }
  }
);