React, Typescript

도전과제 세계부자 리스트 API 받아와서 웹페이지 구성

himzei 2022. 9. 16. 20:22

동영상 강의를 들으면 늘 이해는 가는데 막상 코드챌린지를 해서 과제가 나오면 막막해진다. 

다시 동영상을 보고 나도 비쥬얼 코드만 켜면 마찬가지다. 

 

이번에는 무작정 코드 짜보고 모르는건 구글링으로 도전과제의 의도와는 관계없이 화면 구현에만 집중했다. 

오늘이 첫 포스팅이지만 

앞으로 얼마나 포스팅할 수 있을지 의문이다. 

 

우선 폴더구조는 pages 아래에 about, index, globalStyle 파일을 줬다. 

 

강의에서는 Tailwindcss를 배웠지만 주어진 블루프린트에서는 세팅을 하고 구글링을 해도 잘 몰라서 

npm i styled-components를 활용했다. 

아무래도 Tailwindcss 세팅 후 index.js에서 불러올 때 오류가 나는데 나중에 모법답안 올라오면 확인해 보려한다. 

 

package.json 파일은 아래와 같다. 

{
  "name": "nextjs-blueprint",
  "version": "1.0.0",
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "post-update": "yarn upgrade --latest"
  },
  "dependencies": {
    "autoprefixer": "^10.4.11",
    "next": "latest",
    "postcss-cli": "^10.0.0",
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "react-router-dom": "^6.4.0",
    "styled-components": "^5.3.5"
  },
  "license": "MIT",
  "keywords": [],
  "description": "",
  "devDependencies": {
    "prettier": "^2.7.1",
    "prettier-plugin-tailwindcss": "^0.1.13",
    "tailwindcss": "^3.1.8"
  }
}

크게 index와 about 페이지가 있는데 

api 주소를 통해 데이터를 받아오는 부분은 fetch를 이용해서 받아왔는데 이부분도 강의를 다 보지 않아서 모르겠지만 다른방법이 있을 것 같고, 각각의 세계부자를 클릭 했을때 id 값을 넘겨줄때 useRouter를 이용해 push 해주었다. 이부분도 구글링 해서 찾아낸거지만 아무래도 강의에서는 다를 것 같다. 모법 답안이 기대된다. 

 

index.js

import { useRouter } from "next/router";
import { useState } from "react";
import styled from "styled-components";
import GlobalStyle from "./globalStyle";

const Container = styled.div`
  margin: 40px 0;
`;
const Inner = styled.div`
  width: 1000px;
  margin: auto;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  row-gap: 30px;
  column-gap: 5px;
`;
const FlexBox = styled.div`
  display: flex;
  flex-direction: column;
`;
const ImgBox = styled.img`
  width: 200px;
  height: auto;
  margin-bottom: 5px;
`;
const TitleBox = styled.span`
  font-weight: bold;
`;
const DetailBox = styled.span`
  font-size: 12px;
`;

function IndexPage() {
  const [data, setData] = useState([]);
  const router = useRouter();
  fetch("https://billions-api.nomadcoders.workers.dev/")
    .then((response) => {
      return response.json();
    })
    .then((item) => {
      setData(item);
    });

  return (
    <>
      <GlobalStyle />
      <Container>
        <Inner>
          {data?.map((item) => (
            <FlexBox
              key={item.id}
              onClick={() =>
                router.push({ pathname: "/about", query: { pid: item.id } })
              }
            >
              <ImgBox src={item.squareImage} />
              <TitleBox>{item.name}</TitleBox>
              <DetailBox>{item.industries[0]}</DetailBox>
            </FlexBox>
          ))}
        </Inner>
      </Container>
    </>
  );
}

export default IndexPage;

 

about.js

import GlobalStyle from "./globalStyle";
import { useRouter } from "next/router";
import { useState } from "react";
import styled from "styled-components";

const Container = styled.div`
  margin: 40px 0;
`;
const Inner = styled.div`
  width: 1000px;
  background-color: #3f72af;
  padding: 60px 20px;
  margin: auto;
`;
const Contents = styled.div`
  margin: 80px 0;
  width: 100%;
  height: 100%;
`;
const Wrap = styled.div`
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
`;
const ImgBox = styled.img`
  width: 280px;
  height: 280px;
  margin-bottom: 10px;
`;
const TitleBox = styled.div`
  font-size: 20px;
  color: #f9f7f7;
`;
const ContentBox = styled.div`
  width: 100%;
`;
const TitleBox2 = styled.h2`
  font-size: 30px;
`;
const Grid = styled.div`
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
`;
const GridWrap = styled.div`
  display: flex;
  flex-direction: column;
  border: 1px solid #dbe2ef;
  padding: 10px;
`;

export default function AboutPage() {
  const router = useRouter();
  const pid = router.query.pid;
  const [data, setData] = useState([]);

  fetch(`https://billions-api.nomadcoders.workers.dev/person/${pid}`)
    .then((response) => {
      return response.json();
    })
    .then((item) => {
      setData(item);
    });

  return (
    <>
      <GlobalStyle />
      <Container>
        <Contents>
          <Inner>
            <Wrap>
              <ImgBox src={data.squareImage} />
              <TitleBox>{data.name}</TitleBox>
              <ContentBox>
                Networth : {Math.round(data.netWorth)} millions
              </ContentBox>
              <ContentBox>Country : {data.country}</ContentBox>
              <ContentBox>Industry : {data.industries}</ContentBox>
              <ContentBox>{data.bio}</ContentBox>
            </Wrap>
          </Inner>
        </Contents>
        <Contents>
          <Inner>
            <Wrap>
              <TitleBox2>Financial Assets</TitleBox2>
              <Grid>
                {data?.financialAssets?.map((item, index) => (
                  <GridWrap>
                    <ContentBox>{item.ticker}</ContentBox>
                    <ContentBox>{item.companyName}</ContentBox>
                    <ContentBox>{item.currentPrice}</ContentBox>
                  </GridWrap>
                ))}
              </Grid>
            </Wrap>
          </Inner>
        </Contents>
      </Container>
    </>
  );
}