[Monsters] API 호출로 카드 컴포넌트 만들기 (1)

XCC629·2022년 3월 12일
0
post-thumbnail

React-webucks 프로젝트를 완료하고, 복습하기 위한 작은 프로젝트 monsters를 구현한 방법에 대한 정리를 합니다. (03/12)


프로젝트 목표

  1. useEffect와 fetch를 사용하여 API 호출을 할 수 있다.
  2. props로 부모 component에서 자식 component로 데이터를 전달할 수 있다.
  3. 받은 props 이용하여 component를 재사용할 수 있다.

구현목표 화면

webucks의 list 페이지의 구성과 비슷합니다. 반복하는 구성을 가진 카드들을 나열한 화면입니다.

구성 확인

1. 'Card'컴포넌트

카드 안에서 'image','name', 'email'이 반복됩니다. 이 구성을 하나의 컴포넌트로 구성할 수 있습니다. 컴포넌트의 이름은 Card입니다.

2. 'CardList' 컴포넌트

card들을 나열합니다. api 호출로 받은 데이터를 사용할 것입니다. 그리기 위해서는 먼저 데이터를 받아야합니다.

3. 'Monsters' 컴포넌트

3개 중 가장 부모로, API 호출을 받고 데이터를 저장하는 컴포넌트입니다. API 호출을 하기 위해 fetch와 useEffect, then등을 사용할 것입니다.

정리

Monsters  > CardList > Card 

Monsters가 가장 부모, Card가 최종 자식이 될 것입니다.


1. API 호출하기

Monsters.js

import React, { useState, useEffect} from "react";
import CardList from "./Components/CardList/CardList";
import "./Monsters.scss";

function Monsters() {
  const [monsters, setMonsters] = useState([]);

  // 데이터 로딩
  useEffect(() => {
    fetch("API주소").then(res => res.json()).then(res=>setMonsters(res))
  }, []);

  // SearchBox 에 props로 넘겨줄 handleChange 메소드 정의
  return (
    <div className="monsters">
      <h1>컴포넌트 재사용 연습!</h1>
      <CardList monsters={monsters} />
    </div>
  );
}

export default Monsters;

import

import React, { useState, useEffect} from "react";
import CardList from "./Components/CardList/CardList";
import "./Monsters.scss";

함수형 컴포넌트로 구현하기 때문에 hook을 사용해 상태 관리를 쉽게 합니다. useEffect와 fetch로 받은 데이터를 useState를 통해 갱신할 것입니다. 자식 컴포넌트를 사용하기 위해서 import하고, css 또한 import합니다.

useState

const [monsters, setMonsters] = useState([]);

useState는 변화를 감지하고 리렌더링을 해줍니다. setMonsters를 사용하면 monsters 값을 쉽게 변경할 수 있습니다. useState의 파라미터로 배열을 준 이유는 monsters에 json을 받을 것이기 때문입니다.

API 호출

useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/users")
    .then(res => res.json())
    .then(res=>setMonsters(res))
  }, []);

useEffect에 대한 자세하고 정확한 이용법과 설명은 W3schools(react)React 공식문서(Effect hook 사용하기)를 참고하기를 권합니다.
useEffect를 사용하면 함수형 컴포넌트에서 생명주기 메서드를 사용할 수 있습니다. 처음 렌더링 이후에 useEffect의 첫번째 인자로 들어오는 콜백 함수안의 내용을 실행합니다. 두번째 인자는 Defendency로, useEffect가 어떻게 실행될 것인지를 결정합니다.
fetch는 api를 호출합니다. 그 뒤로 붙은 then 메소드는 데이터를 받아오는 과정에서 오류가 발생하지 않도록 합니다. 이에 관련된 내용은 비동기, MDN 공식문서를 참고하세요.
setMonsters에 res(호출로 받은 데이터)를 넣어서 monsters를 갱신했습니다.

렌더링

return (
    <div className="monsters">
      <h1>컴포넌트 재사용 연습!</h1>
      <CardList monsters={monsters} />
    </div>
  );

react에서는 jsx로 사용할때는 가장 상위 tag 하나가 아래의 tag를 모두 포함하게 해야 합니다. 정해진 규칙입니다. 보통 div를 사용하거나, HTML5부터는 semantic tag를 사용합니다. poiemaweb를 참고하세요. 그 아래의 자식 컴포넌트인 CardList를 넣었습니다.
CardList에 props로 monsters를 줍니다. monsters는 API 호출 과정을 통해 api에서 받은 json이 저장되어 있습니다. 이 데이터를 자식 컴포넌트가 사용할 수 있도록 전달해줍니다. 이때 사용하는 props는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달하는 기능을 합니다.

2. CardList 만들기

CardList.js

import React from "react";
import Card from "../Card/Card";
import "./CardList.scss";

function CardList({monsters}) {
  return 
  <div className="cardList">
    {monsters.map((character) => (
      <Card 
      id={character.id} 
      name={character.name} 
      email={character.email}/>
      ))}
    </div>;
}

export default CardList;

import 설명은 앞에서 했음으로 생략하겠습니다.

함수형 컴포넌트

function CardList({monsters}) {
  return 
  <div className="cardList">
    {monsters.map((character) => (
      <Card 
      id={character.id} 
      name={character.name} 
      email={character.email}/>
      ))}
    </div>;
}

위에서 설명했듯 하나의 tag로 묶어 두었습니다. 위에서 설명했던 대로 card를 나열할 것인데, 하나하나 나열하는 건 react답지도 않고 api로 받은 데이터를 제대로 활용하지도 못합니다. 그렇기에 받은 데이터에 map 메소드를 사용하여 렌더링 해줄 것입니다. map 메소드가 하는 일이 무엇인지 모를 경우에는 MDN을 읽어보세요.
자식이 부모가 준 props는 받는 방법은 함수의 인자로 넣는 것입니다.

jsx에서는 js를 부분을 {}로 감싸주어야 합니다.

받은 데이터의 형식이 json이므로 배열 메소드를 사용할 수 있습니다. 배열 안의 객체를 character에 담아서 dot notation으로 프로퍼티에 접근했습니다.
그리고 또 이 프로퍼티의 값을 props로 자식 컴포넌트인 card에 전달했습니다.

3. Card 컴포넌트 만들기

import React from "react";
import "./Card.scss";

function Card({id, name, email}) {
  return (
  <div className="cardContainer">
    <img 
    src = {`https://robohash.org/${id}?set=set2&size=180x180`} 
    alt="monster" />
	  <h2>{name}</h2>
	  <p>{email}</p>
  </div>);
}

export default Card;

함수형 컴포넌트

function Card({id, name, email}) {
  return (
  <div className="cardContainer">
    <img 
    src = {`https://robohash.org/${id}?set=set2&size=180x180`} 
    alt="monster" />
	  <h2>{name}</h2>
	  <p>{email}</p>
  </div>);
}

CardList 컴포넌트, 즉 부모가 전달해준 props를 인자로 넣어서 받았습니다. 그리고 이 데이터를 카드 구성에 맞게 넣어주면 완성입니다.

img src
기본 모양이 https://robohash.org/(해당id)?set=set2&size=180x180 입니다. scr에 들어가야하는 값은 문자열(string)이고, id 값만 변수로 넣어주면 되기에 백틱을 사용했습니다.


정리

이전까지는 페이지에 들어가야하는 데이터들을 public 폴더에 넣어서 불러왔다면, 지금부터는 api호출을 통해 불러올 수 있습니다. 백엔드와 의사소통을 할 수 있습니다! 👏 또한 react답게 컴포넌트를 재사용하여 UI구현을 보다 편하게 할 수 있습니다.

보완점

useEffect 안 fetch에 then이 아닌 async를 사용하는 방법을 사용할 수 있다면 보다 코드가 간결해질 수 있습니다. 바꿔보고 싶다면 비동기 프로그래밍에 대한 공부가 필요합니다.

profile
프론트엔드 개발자

0개의 댓글