React-webucks 프로젝트를 완료하고, 복습하기 위한 작은 프로젝트 monsters를 구현한 방법에 대한 정리를 합니다. (03/12)
- useEffect와 fetch를 사용하여 API 호출을 할 수 있다.
- props로 부모 component에서 자식 component로 데이터를 전달할 수 있다.
- 받은 props 이용하여 component를 재사용할 수 있다.
webucks의 list 페이지의 구성과 비슷합니다. 반복하는 구성을 가진 카드들을 나열한 화면입니다.
카드 안에서 'image','name', 'email'이 반복됩니다. 이 구성을 하나의 컴포넌트로 구성할 수 있습니다. 컴포넌트의 이름은 Card입니다.
card들을 나열합니다. api 호출로 받은 데이터를 사용할 것입니다. 그리기 위해서는 먼저 데이터를 받아야합니다.
3개 중 가장 부모로, API 호출을 받고 데이터를 저장하는 컴포넌트입니다. API 호출을 하기 위해 fetch와 useEffect, then등을 사용할 것입니다.
Monsters > CardList > Card
Monsters가 가장 부모, Card가 최종 자식이 될 것입니다.
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는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달하는 기능을 합니다.
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에 전달했습니다.
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를 사용하는 방법을 사용할 수 있다면 보다 코드가 간결해질 수 있습니다. 바꿔보고 싶다면 비동기 프로그래밍
에 대한 공부가 필요합니다.