The Modern React Bootcamp / Colt Steele
API와 React Lifecycle methods 중 하나인 componentDidMount를 사용하는 실습이었다. 사실 강의를 들으면서도 이 lifecycle methods를 정확히 어느 때에 사용을 하는건지 잘 모르겠지만, 이 componentDidMount의 경우 API를 fetch할 때 사용하는 거 같다. 리액트의 컴포넌트가 render될 때 constructor - render - componentDidMount 순으로 되는데 이 componentDidMount의 경우 받아오는 데이터가 로딩되기에 좋은 곳이라고 하네... 아무래도 API에서 데이터를 받아오는데 시간이 걸리니까 갖춰져있는 걸 먼저 다 보여준 뒤에 그리고 데이터가 다 받아지면 다시 렌더하는 건가 싶다. 그래서 async/await를 쓰는 거고. 이 강사님도 그렇고, 다른 강사님도 그렇고 fetch를 쓰기보단 axios라는 라이브러리를 써서 fetch를 하더라. 이게 조금 더 깔끔하고 간단한 코드를 쓸 수 있어서 그런 거 같다.
예제에 대한 실습을 먼저 해보고 나서 의문이었던 건 '카드를 어떻게 위에다가 제각기 쌓을 수 있는가' 였다. 내가 API를 받아오고 버튼을 누르면 카드가 보이게까지는 했는데 카드가 한 장씩 따로 보이지 않는 것. 이건 결국 스타일링으로 해결할 수 있었다. 그리고 전에 JS 강의를 들을 때 error도 반드시 잘 다룰 수 있어야 한다고 강조했는데, 이 실습에서 그걸 또 한 번 강조했다. ...사실 잊고 있었다. API를 다룰 땐 에러 역시 다룰 수 있어야 한다는 걸.
컴포넌트의 구성은 App > Deck > Card
class Deck extends React.Component {
.
.
componentDidMount = async () => {
const { data } = await axios.get(`${BASE_URL}/new/shuffle`);
this.setState({
deck: data,
remaining: data.remaining,
DECK_ID: data.deck_id
});
};
axios로 받아온 데이터를 다시 변수에 할당하고 그걸 setState를 이용해서 state를 바꿔주었다.
onBtnClick = async () => {
try {
const { data } = await axios.get(
`${BASE_URL}/${this.state.DECK_ID}/draw/`
);
if (!data.success) throw new Error('No card remaining 🃏');
const cards = data.cards[0];
this.setState(state => ({
drawn: [
...state.drawn,
{
id: cards.code,
name: `${cards.value} of ${cards.suit}`,
image: cards.image
}
]
}));
} catch (err) {
alert(err);
}
};
그리고 내가 흥미롭게 본 코드. try와 catch를 에러도 다룰 수 있게 코드를 썼다. 카드의 갯수가 52장이고 조건을 remaining === 0이 아닌 !data.success로 한 건 마지막 한 장까지 받아오기 위해서인다. success: false일 때, 이 에러를 다루기 위해서 쓴 코드. 물론 에러를 다룰 때는 저렇게 alert으로 대체하면 안되지만... 전에 JS 강의 들을 때 에러를 사용자가 볼 수 있도록 코드를 썼었는데 기억이 나질 않네. 다시 한 번 복습하러 가야겠다. 여튼 API에서 받아온 데이터를 state.drawn 배열에 하나씩 차곡차곡 넣는다. 그래서 이걸로 map을 이용해 하위 컴포넌트인 Card에 props으로 데이터를 전달한다.
그러면 이제 의문, 카드를 어떻게 한 장씩 랜덤으로 따로 따로 엇갈리게 놓을 수 있을까.
class Cards extends React.Component {
constructor(props) {
super(props);
const positionX = Math.random() * 40 - 20;
const positionY = Math.random() * 40 - 20;
const angle = Math.random() * 90 - 45;
this._transform = `translate(${positionX}px, ${positionY}px) rotate(${angle}deg)`;
}
render() {
return (
<img
className="Card"
style={{ transform: this._transform }}
src={this.props.image}
alt={this.props.name}
/>
);
}
}
버튼을 누를 때마다 카드를 한 장씩 받아오게 했는데 이걸 렌더 자체에서 실행하면 버튼을 누를 때마다 전에 받아온 카드까지 전부 다 다시 렌더되기 때문에 새롭게 받아온 카드만 랜덤으로 놓일 수 있도록 constructor에 설정을 했다. 이렇게 코드를 쓰니 새롭게 받아온 카드만 이미 받아온 카드 위에 놓이게 된다. (물론 카드의 position: absolute를 해줘야 함)
의문인 건 이 카드를 저렇게 또 새롭게 받아오도록 해야하는 것이다. 버튼을 누를 때마다 API가 매번 호출이 되는데 카드를 한 번만 다 받아와서 한 장씩 보여주게 할 순 없을까 라는 생각이 스쳤다. 그래서 deckofcards api에 들어가서 문서를 봤는데 deck_id마다 52개의 카드가 주어지고 이걸 한 장씩 받아오려면 또 다른 api를 써야해서 그런가 싶기도 하고... 어떻게 하는 게 제일 좋은 지 몰라서 의문인 것.
'Front End > React' 카테고리의 다른 글
[React] Hook으로 카카오맵 API 사용하기 | 마커 표시, 커스텀 오버레이 (0) | 2021.12.13 |
---|---|
[React] this.setState는 두번째에서 콜백을 받는군요...? (0) | 2021.09.02 |
[React] To Do List (0) | 2021.08.31 |
[React] return을 알맞게 써줘야 합니다. (0) | 2021.08.31 |
[React] Lights Out : 셀의 불을 모두 끄자 (0) | 2021.08.30 |
댓글