본문 바로가기

리액트

리액트 일지 003 | 리액트 배열 렌더링하기 | API 연동하여 데이터 출력하기 | 리액트 배열 오류

에러로그

 아래와 같이 음식 데이터를 받아와 화면에 출력하는 메뉴판을 만들던 중, 데이터를 배열로 받아와 출력하는 과정에서 여러가지 에러를 만났다. 분명 이전에 리액트 배웠을 때엔 배열을 가져와서 배열을 저장하고 map 함수를 써서 출력해주었던 것 같은데 다른 내용으로 시도해보았을 때 잘 안됐어서 좀 많은 시간을 소비했다ㅠㅠ 

 

구현하고 싶었던 화면

나의 멋진 해결

 타입스크립트에서는 타입 명시를 보다 명확하게 해주어야하는데 그 부분이 부족했다. 

 

 이렇게 recoMenu라는 이름으로 useState를 설정하고 axios.get을 통하여 데이터를 받아온 뒤 두번째 인자에 배열을 저장해주었다. 오류가 난 근본적인 이유는 배열도 명시적으로 입력해주어야하는데 그렇지 않으면 암시적으로 항상 비어있는 항상 비어있는 배열을 가져오기 때문이였다(never[]) 이에 useState를 <any[]>로 명시해주었더니 에러가 싹 사라졌다! 오랜 시간 고민했던 것 치고는 약간 허무한 해결,, 코드 전문은 아래와 같다. 

 

/* eslint-disable no-unused-vars */
import React, { useEffect, useState } from 'react';
import * as S from './style';
import axios from 'axios';

export const ResultMenu = () => {
  const bmi = localStorage.BMI;
  //useState로 상태 저장해주기
  const [recoMenu, setRecoMenu] = useState<any[]>([]);
  //api 통신으로 데이터 받아오기
  async function getMenu() {
    try {
      axios.get(`url`).then((response) => {
      //데이터 배열을 state setter(두번째인자)에 저장
        setRecoMenu(response.data.data);
      });
    } catch (error) {
      console.log(error);
    }
    console.log(recoMenu);
  }
  useEffect(() => {
    getMenu();
  }, []);

  return (
    <>
    //styled-components 변수명들(S.~)
      <S.Wrapper>
        Menu
        <button onClick={getMenu}>test</button>
        <div>
        //map 함수 사용하여 key값에 따라 출력해주기
          {recoMenu.map((name) => (
            <S.MenuWrapper key={name.id}>
              <S.MenuImg>이미지</S.MenuImg>
              <S.TextWrapper>
              //데이터 배열에 따른 foodNm과 calorie를 각각 출력, (하단 이미지는 이름만 출력)
                <S.MenuName>{name.foodNm}</S.MenuName>
                <S.MenuKcal>{name.calorie}Kcal</S.MenuKcal>
              </S.TextWrapper>
            </S.MenuWrapper>
          ))}
        </div>
      </S.Wrapper>
    </>
  );
};

 

그러면 요렇게 이름이 잘 출력된다.
CSS까지 붙이면 이렇게 첫 캡쳐사진과 비슷하게 잘 출력된다! 배경색 지우는건 깜박했다

내가 한 삽질 

 사실 타입 오류 때문인지는 모르고 처음엔 별 시도를 다 해봤다.ㅠㅠ map 함수도 뜯어보고, useEffect도 달아보고, index도 달아보고,,,,, 별 거 별 거 다 해봤는데 소득 없는 시도였던 것이였다... 최초의 오류는 Uncaught Error: Objects are not valid as a React child (found: object with keys {id, foodNm, calorie, img, irdntNames}). If you meant to render a collection of children, use an array instead. 그 다음 봤던 에러는 Property 'calorie' does not exist on type 'never'.

 

 처음 이런 에러가 떴을 때에는 인터페이스로 타입 명시도 해주었는데 사실 이때는 배열을 받아다 리턴할 때 적었던 형식이 잘못됐기때문에 에러가 난 것 같기도 하다. 이때는 배열을 정의하고 map함수로 정리해다가 {배열명}으로 리턴했었는데 처참하게 실패했다. Uncaught Error: Objects are not valid as a React child (found: object with keys {id, foodNm, calorie, img, irdntNames}). If you meant to render a collection of children, use an array instead. 이 에러가 배열을 리턴해야하는데 데이터로 받아온 객체 그 자체를 출력하고자 했기에 발생하는 에러같았다. 

 

행복하게 코딩하고자 변수명도 happy로 지었다,,,☆★ 후에 위의 코드처럼 name으로 수정해주었다.

 이렇게 map을 써서 함수를 제대로 리턴하였을 때에도 어김없이 에러가 떴는데 배열의 각 프로퍼티로 정렬을 하려하는데 사용하는 프로퍼티마다 에러가 났다. Property 'calorie' does not exist on type 'never'. 이 부분이 배열 타입 명시가 필요했었던 부분인 <any[]> 를 배열에 추가하여 멋지게 해결하였다. 타입스크립트의 세계란 아직도 멀고도 어렵고도 험한 것 같다.