[실전 React.js] Part3. 리스트 구성하기

axios를 이용한 데이터 호출

박성은
hivelab-dev
11 min readDec 24, 2019

--

지난 Part2. 프로젝트 시작하기에 이어, 이번 파트에서는 상품 아이템 데이터를 가져와 아래와 같은 화면을 구성할 것입니다. 레이아웃은 옥션의 아이템 리스트를 참고하였습니다.

Demo: http://fe.hivelab.co.kr/itemlist

스펙 확인 / 폴더 구조 설계

기능별 또는 ui별 컴포넌트를 쪼개 구조화하는 방식으로 개발합니다.

  • 페이지 : 아이템 리스트 페이지(lp.js), 장바구니 페이지(cart.js)
  • 기능 : 아이템 정렬, 필터, 보기 방식 변경 / 장바구니 추가, 삭제
react-itemlist // 프로젝트명

└ src
├ layout ─ header.js //헤더 (페이지 네이게이션)

├ page ┬ components ┬ itemcard.js // 상품 아이템 레이아웃
│ │ ├ cartitem.js // 장바구니 아이템 레이아웃
│ │ ├ sort.js // 정렬
│ │ ├ filter.js // 필터 레이어
│ │ └ viewtype.js // 상품보기 방식 선택
│ │
│ ├ lp.js // 아이템리스트 페이지
│ └ cart.js // 장바구니 페이지
├ index.js
├ App.js
└ App.css

컴포넌트 설계 시 고려사항

  1. state로 관리하고, 어떤 내용을 props로 내려주는지를 생각해야합니다.
  2. 컴포넌트간의 관계를 고민해보며 구조화하는 것이 중요합니다.
  3. 다른 컴포넌트들끼리 props를 교환하면 컴포넌트 갯수가 많아진 경우 구조가 굉장히 복잡해 질 수 있습니다. 따라서 부모를 거쳐서 내려받도록 합니다.
  4. 이번 예제에서는 App.js를 통해 state를 관리하도록 설계하였습니다.
예제파일 데이터 흐름도

하위 컴포넌트에서 일어난 Events 를 통해 액션을 전달 받고, App.js에서 상태 변화가 일어나면 변경된 Data는 다시 하위 컴포넌트에 전달됩니다.

Step1. 상품 리스트를 출력해보자.

  • 작성 파일 : App.js / lp.js / itemcard.js
  • App.js : 데이터를 주고 받고 저장하며, 하위 컴포넌트(lp.js/cart.js)의 데이터 변화를 연결시켜주는 중심 컴포넌트
  • lp.js : 아이템 카드를 반복시켜 리스트를 출력하는 컴포넌트
  • itemcard.js : 아이템 카드를 구성할 각각의 DOM을 생성하는 컴포넌트
  1. 아이템 리스트 페이지 생성

App.js를 아래와 같이 작성해봅니다.
먼저 빈 ItemList 배열을 state에 선언하고 화면에 보여질 부분을 reader() 함수 안에 넣습니다.

ItemList 가 호출되지 않은 경우를 대비해 loading 값도 미리 선언해줍니다.

//App.js
import React, { Component } from "react";
class App extends Component {
state = {
loading: false,
ItemList: [] // 비어있는 배열
};
// APP.js 컴포넌트의 최종 보여지는 render값 정의
render() {
return (
<div>
<Listpage />
</div>
);
}
}export default App;

2. axios를 이용해 json 파일 불러오기

예제로 쓰이는 데이터는 옥션 검색 페이지 API일부를 가져왔습니다. 아래와 같은 데이터는 보통은 개발 요청에 맞게 백엔드단에서 전달해줍니다.

"Item": [
{
"GoodsCode": "1625717680",
"OriginalPrice": "29,800",
"SalePrice": "26,230",
"GoodsName": "달콤나시(OBWC5266)(갤러리아)",
"DiscountRate": "11",
"Delivery": {
"DeliveryInfo": "조건부무료",
"DeliveryText": "배송비 3,000원",
"DeliveryType": "GRAY",
"ShowDeliveryInfo": true
}
},
{
"GoodsCode": "1421117680",
"OriginalPrice": "9,800",
"SalePrice": "7,700",
"GoodsName": "나시(현대)",
]
...
...

이제 axios 라이브러리를 사용해 API를 호출해 줄 것입니다.

axios는 promise API를 기반으로 하는 비동기 통신 라이브러리로, npm/yarn에서 설치할 수 있습니다.

설치가 완료되면, App.js에 import 해줍니다.

import React, { Component } from "react";
import axios from "axios"; // 설치 후 import
class App extends Component {
state = {
ItemList: []
};
....
}

state 선언과 함께 아래에 데이터를 가져오는 loadItem 라는 함수를 만들어 줄 것 입니다.

이 함수에서 데이터는 axios.get으로 요청해 .then으로 응답값을 받아올 수 있고, 받아온 data.Item 로 만들어놓은 ItemList 배열 state값을 변경합니다.

데이터를 가져옴과 함께 미리 만들어놓은 loading 속성값도 true로 변경해줍니다.

  state = { 
loading: false,
ItemList: []
};
loadItem = async () => {
axios
.get("./SearchJson.json")
.then(({ data }) => {
this.setState({
loading: true,
ItemList: data.Item
});
})
.catch(e => { // API 호출이 실패한 경우
console.error(e); // 에러표시
this.setState({
loading: false
});
});
};
render() {
...
}
}

loadItem() 함수 작성이 완료되었다면 componentDidMount()를 사용해 호출하는데, 앞서 설명했었듯이 componentDidMount()는 update전 컴포넌트에서 필요한 데이터를 요청하기위한 외부API를 호출하는 경우 주로 쓰입니다.

참고 : [실전 React.js] Part1. 개념 이해하기

  componentDidMount() {
this.loadItem(); // loadItem 호출
}
render() {
...
}

여기까지 작성했다면 아이템리스트 API가 잘 불러와졌는지 확인해봅니다.

render() {
const { ItemList } = this.state;
console.log(ItemList);
출력 : console.log(ItemList);

3. 아이템 리스트 DOM 생성

이제 아이템 리스트 페이지 html을 구성할 컴포넌트를 작성해 볼 것입니다.

  • lp.js : 아이템 카드를 반복시켜 리스트를 출력하는 컴포넌트
  • itemcard.js : 아이템 카드를 구성할 각각의 DOM을 생성하는 컴포넌트

App.js를 시작으로 itemcard.js까지 부모에서 자식 컴포넌트로는 Props가 전달되고, itemcard.js에서부터는 Event가 전달되어 setState()값을 변화시켜줍니다.

우선 하나의 상품 데이터가 출력될 컴포넌트를 작성해봅니다.

ItemCard 컴포넌트는 아래와 같이 함수형 컴포넌트로 작성하였으며, 화면에 보여져야하는 값들을 정리하여 파라미터 값으로 넘겨줄 것입니다.

여기서 key는 각 상품마다 고유의 값으로 지정해주는데에 쓰이고, 아래와 같이 이미지 URL, 브랜드명, 상품명을 넣어줄 변수들을 각각의 자리에 지정해줍니다.

// itemcard.js
function ItemCard({ key, ImageURL, BrandName, GoodsName }) {
return (
<li className="component component--item_card" key={key}>
<img src={ImageURL} className="image--itemcard" alt="" />
<p>
브랜드명 : <span className="text--brand">{BrandName}</span>
</p>
<p>상품명 : {GoodsName}</p>
</li>
);
}

4. 데이터가 들어간 ItemList 배열 렌더링하기

먼저 lp.js에서 ItemCard 컴포넌트를 render()함수에 호출해줍니다.

<ItemCard ImageURL={data.ImageURL} /> 이렇게하면 DOM이 호출되는데,

미리 파라미터 값으로 만들어놓은 ImageURL 이라는 속성에 data.ImageURL 값을 넣어주는 식으로 작성하면 데이터가 ItemCard 컴포넌트에 전달됩니다.

ItemCard 컴포넌트를 json 배열만큼 반복시켜 출력하기위해 map()을 사용해 여러개의 데이터를 순차적으로 return 시켜줍니다.

// lp.js
import React, { Component } from "react";
import ItemCard from "./components/itemcard";
class Listpage extends Component {
state = {};
render() {
const { Itemcard } = this.props;
return (
<ul className="list__itemview">
{Itemcard &&
Itemcard.map((itemdata) => {
return (
<ItemCard
ImageURL={itemdata.ImageURL}
BrandName={itemdata.BrandName}
GoodsName={itemdata.GoodsName}
/>
);
})}
</ul>
);
}
}
export default Listpage;

그리고나서 App.js에 지금까지 만든 아이템 리스트를 최종적으로 render해주면,

//App.js
import React, { Component } from "react";
import Listpage from "./page/lp";
.... render() {
console.log(ItemList);
return (
<div>
<Listpage Itemcard={ItemList} />
</div>
);
}

App.js 를 render하고있는 index.js가 최종적으로 화면에 노출시켜줄 것입니다.

이상 axios이용해 API를 호출하고, 상품리스트를 출력하는 방법에 대해 소개하였습니다. 다음 Part에서는 필터(Filter) 정렬(Sort), 토글(Toggle)과 같은 기능을 구현하는 내용을 다루겠습니다.

아래 링크를 통해 직접 코드를 보면서 연습해보시는 것을 추천드립니다 :)

http://t.ly/k2E1m

시리즈 정보

🔍 하이브랩과 함께 할 멋진 FE개발자를 찾고 있습니다.

--

--