언어/Next.js

[Next 고캠핑]공공데이터포털 API 불러오기

홍시_코딩기록 2024. 7. 16. 22:17

 

캠핑 사이트를 만드려고 공공데이터포털에서 캠핑 api를 신청했다.

 

 

인증키는 최상단에 .env파일을 만들어서 NEXT_PUBLIC_SERVICE_KEY  인증키를 넣어준다.

next.js는 NEXT_PUBLIC  을 붙여줘야 함.

리액트는 REACT_APP 

 

<완성 화면>

하단 아이콘은 아직 작업 전

 

나는 캠핑장 정보를 카드 형태의 리스트로 제공하고 싶었다.

 

 

interface ICampingList {
  facltNm: string;
  lineIntro?: string;
  addr1: string;
  firstImageUrl?: string;
  themaEnvrnCl?: string;
  tel: string;
  contentId: number;
}

interface IApiResponse {
  response: {
    body: {
      items: {
        item: ICampingList[];
      };
    };
  };
}

interface IPropsList {
  className?: string;
}
export default function CampingCard({ className }: IPropsList) {
  const [list, setList] = useState<ICampingList[]>([]); //데이터
  const [loading, setLoading] = useState<boolean>(false); //로딩
  const SERVICE_KEY = process.env.NEXT_PUBLIC_SERVICE_KEY; //인증키

  useEffect(() => {
    async function fetchData(): Promise<void> {
      setLoading(true);
      try {
        const response = await axios.get<IApiResponse>(
          `http://apis.data.go.kr/B551011/GoCamping/basedList?serviceKey=${SERVICE_KEY}&numOfRows=10&pageNo=1&MobileOS=AND&MobileApp=appName&_type=json`,
        );
        setList(response.data.response.body.items.item);
        console.log(list);
      } catch (e) {
        console.error(e);
      }
      setLoading(false);
    }
    void fetchData();
  }, [SERVICE_KEY]);

  if (loading) {
    return <Loading>대기 중..</Loading>;
  }

  if (!list) {
    return null;
  }
  return (
    <>
      {list.map((item: ICampingList) => (
        <CardWrap key={item.contentId} className={className}>
          <CardInner>
            <ImgBox>
              <LikeBtn className="like" />
              <img src={item.firstImageUrl} alt={item.facltNm} />
            </ImgBox>
            <CardInfo>
              <li>
                <strong>{item.facltNm}</strong>
              </li>
              <li>{item.lineIntro ? item.lineIntro : item.themaEnvrnCl}</li>
              <li className="address">{item.addr1}</li>
              <li>{item.tel}</li>
            </CardInfo>
          </CardInner>
          <IConWrap>
            <li>
              <i>icon</i>
            </li>
            <li>
              <i>icon</i>
            </li>
            <li>
              <i>icon</i>
            </li>
          </IConWrap>
        </CardWrap>
      ))}
    </>
  );
}

 ICampingList 내가 가져올 데이터들을 타입 선언 해주고

setList에 데이터를 담는데 이런 오류가 나왔다.

Unsafe argument of type `any` assigned to a parameter of type `SetStateAction<ICampingList[]>`.

 

axios 응답 데이터의 타입을 명확히 지정하지 않아서 발생한다고 한다.

콘솔로 확인해보면 내가 찾는 데이터까지 response.data.response.body.items.item 으로 가야해서 

IApiResponse 으로 api 데이터 타입을 선언 해 줬다.

 

IPropsList 부모 컴포넌트에서 클래스 줘서 디자인 할 수도 있으니까 프롭스로 클래스 정해줌.

 

고캠핑 활용메뉴얼을 보면 json파일은 &_type=json을 추가하라고 나온다. 저거 안쓰면 XML로 받아와짐.

페이지는 나중에 변수로 지정해서 추가할 것이나 일단은 1로 정함.

 

데이터가 불러와지기 전에 로딩창을 보여주고 불러와지면 false

다 된 것 같았는데 

이 놈이 날 괴롭힘. 다시 검색

https://stackoverflow.com/questions/43980188/what-could-this-be-about-tslint-error-promises-must-be-handled-appropriately

 

What could this be about? [TsLint Error: "Promises must be handled appropriately"]

I'm doing some basic asynchronous operations using async/await in TypeScript but TSLint is throwing mysterious error messages for these two functions below. Has anyone encountered these errors befo...

stackoverflow.com

 

void를 사용하면 타입스크립트에게 이 호출의 반환 값을 무시하겠다는 의도를 전달할 수 있어서 경고 메세지 피하면서 호출할 수 있는 간단한 방법이라고 한다..

 

 

 

먼저 콘솔로 확인. 음 잘 나온다.

그리고 map으로 데이터들을 넣어서 화면에 출력해줌.