본문 바로가기
Web Development/React

React / 컴포넌트가 마운트 될 때 fetch로 서버에서 받아오는 데이터 값이 없어서 생기는 오류 해결

by Krystal K 2023. 5. 17.

컴포넌트가 마운트 될 때 

fetch로 서버에서 받아오는 데이터 값이 없어서 생기는 오류 해결

데이터가 들어오기 전에는 값을 출력하지 않고 다시 데이터를 요청하도록 


 

구현하려는 기능 

네비게이션에 서버에서 받아온 userdata를 활용해서 포인트와 상품 수량 출력

 

 

내가 생각한 로직

1. 서버에서 받아오는 유저 데이터는 계속해서 값이 변하기때문에 useState를 사용해서 관리한다.

2. fetch를  사용하여 서버에서 데이터를 받아온다.

3. 받아온 데이터를 state에 저장하고 각각의 데이터를 쓰임에 맞게 가공해서 변수로 선언한다.

 

 

 

처음 작성했던 코드 (오류 발생)

  useEffect(() => {
    fetch("http://10.58.52.169:9001/users", {
      method: "GET",
      headers: { Authorization: token },
    })
      .then(res => res.json())
      .then(data => {
        setUserData(data);
      });
  }, []);

  useEffect(() => {
    fetch("http://10.58.52.169:9001/carts", {
      method: "GET",
      headers: { Authorization: token },
    })
      .then(res => res.json())
      .then(data => {
        setMyCart(data);
      });
  }, []);

  const myPoint = Math.floor(user.points);
  const cartCount = myCart.length;

 

1. 서버에서 받아오는 유저 데이터는 계속해서 값이 변하기때문에 useState를 사용해서 관리한다.

const [userData, setUserData] = useState([]);

 

 

2. fetch를  사용하여 서버에서 데이터를 받아온다.

useEffect(() => {
    fetch("http://10.58.52.169:9001/users", {
      method: "GET",
      headers: { Authorization: token },
    })
      .then(res => res.json())
      .then(data => {
        setUserData(data);
      });
  }, []);

  useEffect(() => {
    fetch("http://10.58.52.169:9001/carts", {
      method: "GET",
      headers: { Authorization: token },
    })
      .then(res => res.json())
      .then(data => {
        setMyCart(data);
      });
  }, []);

 

 

 

3. 받아온 데이터를 state에 저장하고 각각의 데이터를 쓰임에 맞게 가공해서 변수로 선언한다.

 const myPoint = Math.floor(user.points);
 const cartCount = myCart.length;
 ...
 return (
 ...
 	<li> My Point : {myPoint}P </li>
 ...
     <li> Cart <span className="cartCountButton">{cartCount}</span> </li>
 )

 

 

오류가 발생한 부분

네비게이션 바에서 MyPoint와 cart의 상품 수량을 표시하는 부분에서 에러가 발생했다.

유저 데이터를 가공해서 사용하는 mypoint와 cartCount가 값을 찾지 못해 발생한 에러였다.

 

 

오류가 발생한 원인

새로고침을 하면 값이 정상적으로 들어오는 것을 확인했다.

즉 랜더링을 다시 할 때 값이 정상적으로 들어오는 것을 알 수 있었고, 

처음 랜더링 될때는 값을 불러오지 못해 생긴 오류라는 것을 유추할 수 있었다.

 

useEffect는 return이 끝난 후에 실행이 된다.

따라서 useEffect 안에 있는 fetch도 return후에 실행이 된다.

문제는 fetch로 받아온 유저 데이터를 return해야하는데 랜더링이 처음 실행 될 때에는

유저 데이터가 들어오지 않은 상태로 return이 실행되고, 그 후에 유저 데이터가 들어오게 된다.

 

따라서 유저 데이터가 들어오지 않은 상태로 return이 실행되면서

그 안에 유저데이터의 값을 사용하는 부분에서 에러가 발생했다.  

 

 

해결 방안

유저데이터를 불러온 후에 return을 하도록 수정하면 데이터가 없어서 발생하는 오류를 해결할 수 있을 것 같았다.

그래서 가져오는 데이터가 없을 경우에는 return이 실행되지 않도록 아래와 같이 코드를 추가했다.

 

  if (!user) return null;
  if (!myCart) return null;

 

 

BUT! 또다른 오류 발생!!

 

오류가 발생한 부분

토큰 없을 경우에는 네비 자체가 사라져버리는 이상한 오류가 발생했다.

임의로 token이라는 변수에 값을 넣어 토큰이 있도록 했더니 네비가 나타났다.

원인을 파악하기 위해 모든 코드들을 주석처리하고 하나씩 테스트를 했다.

결론적으로 바로 위에서 해결방안으로 추가 했던 코드가 문제의 원인이었다.

 

 

오류 발생 원인

여기서 중요한 포인트는 유저 데이터는 토큰이 있을 경우에만 가져올 수 있기 때문에

토큰이 없을 경우에는 유저 데이터 요청 자체가 안된다. 

유저 데이터가 없을 경우 null을 리턴하도록 했더니

토큰이 없어서 유저 데이터가 없을 경우 아무것도 리턴하지 않아 네비 자체가 사라져버린 것이었다.

 

 

해결 방안

유저 데이터를 조건으로 사용하는 것은 적절하지 않다는 판단이 들었다.

그래서 토큰의 유무에 따라 fetch를 실행하도록 코드를 수정했다.

if (!token) return;

useEffect 안에 fetch가 실행 되기전, 조건문으로 토큰이 없을 경우 early return을 실행시켜 fetch가 실행되지 않도록 했다.

 

 

수정된 코드

 useEffect(() => {
    if (!token) return;
    fetch(`${API_ADDRESS}users`, {
      method: "GET",
      headers: { Authorization: token },
    })
      .then(res => res.json())
      .then(data => {
        setUserData(data);
      });
  }, []);
  
  useEffect(() => {
    if (!token) return;
    fetch(`${API_ADDRESS}carts`, {
      method: "GET",
      headers: { Authorization: token },
    })
      .then(res => res.json())
      .then(data => {
        setMyCart(data);
      });
  }, []);

 

그리고 유저 데이터가 없을 경우를 조건부 랜더링으로 출력값을 지정해 주었다.

 

 

 

최종 수정된 코드

 

useEffect 의존성 배열에 token과 mycart를 넣어 값이 변할 때마다 업데이트되어 출력되도록 했다.

mypoint를 쓰지않고 token과 mycart만 사용한 이유는

mypoint의 경우 유저 데이터에서 받아오게 되는데 결제가 완료되고 포인트를 사용해야 값이 변한다.

 

하지만 mycart는 사용자가 카트에 상품을 추가할 때마다 계속해서 데이터가 업데이트 된다.

따라서 mycart는 값이 변경 될 때 마다 계속 리랜더링을 해줘야 네비게이션에 해당 값이 바로 적용되어 출력된다.

 

그리고 token값을 의존성 배열에 넣은 이유는 로그인이 되면 유저 데이터를 불러와야 하기 때문이다.

내가 구현한 로그인 기능은 로그인페이지로 이동하지 않고 모달창으로 로그인을 진행하기 때문에

로그인이 이루어진 이후에 랜더링이 진행되지 않는다.

그래서 강제로 리랜더링을 해야하기 때문에 의존성 배열에 토큰을 넣어서 로그인할 경우 다시 랜더링 되도록 했다.

 

추가적으로

불필요하게 분리되어있던 fetch를 하나의 useEffect안에 넣어 중복되는 코드를 줄였다.

 

728x90