[ReactJS_MasterClass] #5 CRYPTO TRACKER (1)

유은선·2023년 1월 25일
0

ReactJS_MasterClass

목록 보기
4/11
post-thumbnail

✍5.0 Setup

React Query 패키지는 편리한 방식으로 데이터를 fetch 시킬 수 있다.

리액트 쿼리를 배우기 전에 우리가 아는 방식으로 데이터를 fetch 시켜보자.

✔️react-query 설치

npm i react-query

path="/:coinId"는 Router에게 URL이 변수값을 갖는다는 걸 말해주는 방식!

<Route path="/:coinId" element={<Coin />} />

✍5.1 Styles

✔️CSS Reset
createGlobalStyle : 한 컴포넌트를 만들게 해주는데, 렌더링 될 때 그 컴포넌트는 전역 스코프에 스타일들을 올려준다.
https://github.com/zacanger/styled-reset/blob/master/src/index.ts
<></> (Fragment) : 일종의 유령 컴포넌트, 부모가 없이 서로 붙어있는 많은 것들을 리턴하게 해준다.

✔️폰트 설치
https://fonts.google.com/

✍5.2 Home part One

coinpaprika api 이용해서 실습
https://api.coinpaprika.com/v1/coins

Coins에서 각 코인들을 누르면 세부 페이지로 이동하게 할건데, <a href="">을 쓰면 페이지가 새로고침되어 버리기 때문에 link를 이용하지 않을 것이다. 대신에 react router dom을 통해 link component를 사용!

✍5.3 Home part Two

API로부터 데이터를 fetch(가져오기)하는 파트

특정한 시기에만 코드를 실행하기 위해 useEffect function을 사용한다.

여기서 작은 팁이 있는데, 함수를 따로 선언하지 않고 바로 실행가능한 함수를 선언할 수 있다.

useEffect(() => {
    (() => console.log("바로 실행"))();
  }, []);

(      )( ); 안의 함수를 바로 실행 가능!

coin 개별화면에서 coins 화면으로 넘어갈 때마다 "Loading..." 문구를 계속 볼 수 있다.
이유는 screen이 바뀔 때 state가 사라지고 마찬가지로 Coins screen에서 coin 개별화면으로 갈때도 가지고 있던 모든 state가 사라지기 때문에 사용자가 다시 돌아올때마다 API를 다시 fetch 하기 때문이다. (바람직한 방법이 아님)

✍5.4 Route States

Crypto Icon API : https://coinicons-api.vercel.app/

5.3에서 다른 페이지에서 다시 올 때마다 새로 load 해야 하는 문제점은 여전히 남아있다. 5.4의 코드에서는 Coin component에서 API를 직접 부르지 않으면서 데이터를 넘겨줄 수 있다.

//Coins.tsx
<Link to={`/${coin.id}`} state={coin.name}>

//Coin.tsx
function Coin() {
  const [loading, setLoading] = useState(true);
  const { coinId } = useParams();
  const { state } = useLocation();
  console.log(state);

  return (
    <Container>
      <Header>
        <Title>{state || "Loading..."}</Title>
      </Header>
      {loading ? <Loader>Loading...</Loader> : null}
    </Container>
  );
}

만약 시크릿창에서 coin 개별화면으로 바로 접속하려고 하면 에러가 나거나 정보가 제대로 뜨지 않을 것인데, state가 생성되려면 Home 화면을 먼저 열어야 하기 때문이다. 클릭했을 때 state가 만들어지므로 그 다음 coin 개별화면이 state를 가져서 Title 등을 보여줄 수 있다.

state가 존재하면 name을 가져오고, state가 존재하지 않을때는 "Loading..."문구를 보여주게 된다.
✅1. 따라서 시크릿모드에서 상세화면 URL을 바로 치고 들어오면 Loading 화면을 보게 되고,
✅2. Home 화면을 통해 들어온다면 클릭을 통해 생성된 state를 보게 될 것이다.

바로 위의 코드에서는 시크릿모드로 들어가도 따로 오류화면이 나오지 않는데, 밑의 코드에서는 오류화면이 뜨는 것을 확인할 수 있을것이다.
이 문제점을 해결하기 위해서는 state 뒤에 ? 만 적어주면 된다.
추가되고 달라진 코드는 아래와 같다.

//Coins.tsx
<Link to={`/${coin.id}`} state={coin}>

//Coin.tsx
interface LocationState {
  state: {
    name: string;
  };
}

const { state } = useLocation() as LocationState;

<Title>{state?.name || "Loading..."}</Title>

✍5.5 Coin Data

코인 정보 링크
🔗https://api.coinpaprika.com/v1/coins/btc-bitcoin
코인 가격 정보 링크
🔗https://api.coinpaprika.com/v1/tickers/btc-bitcoin

이제 url을 fetch 해올건데, 코드를 한줄로 쓰는 방법도 존재한다.

const response = await fetch(`https://api.coinpaprika.com/v1/coins/${coinId}`);
const json = await response.json();
   
//위 두줄과 같은 코드, 캡슐화
const response = await (await fetch(`https://api.coinpaprika.com/v1/coins/${coinId}`)).json();

추후에 React query를 사용해서 더 좋은 코드를 작성해보자.
이제 useState({})를 활용해서 info, price 데이터를 받아올건데 typescript는 항상 빈 object일거라고 생각하기 때문에 오류가 날것이고, 따라서 type을 알려주는 과정이 필요하다. (5.6에서 다뤄본다)

 const [info, setInfo] = useState({});
 const [price, setPriceInfo] = useState({});

  useEffect(() => {
    (async () => {
      const infoData = await (
        await fetch(`https://api.coinpaprika.com/v1/coins/${coinId}`)
      ).json();
      const priceData = await (
        await fetch(`https://api.coinpaprika.com/v1/tickers/${coinId}`)
      ).json();
      setInfo(infoData);
      setPriceInfo(priceData);
    })();
  }, []);

✍5.6 Data Types

TypeScript를 위해 data type을 알아보자.
1. infoData와 priceData 를 console.log로 찍어보기
2. 콘솔창에서 각 데이터 객체를 우클릭하여 전역변수로 object 저장 클릭
3. 각각 temp1, temp2로 저장이 되는데, Object.keys(temp1).join()을 이용하여 string을 얻고, infoData와 priceData 각각에 넣어서 타입을 써주면 된다.
4. 쉼표를 ctrl+D 해서 모두 선택하고, 지운다음 엔터를 치면 쉽게 작성이 가능!
5. 그 다음 모두 드래그해서 alt+shift+i를 누르면 선택한 모든 문자열의 가장 우측 끝으로 포커싱이 되므로 :을 모든 줄에 작성이 가능하다.
6. 이제 value를 가져올건데, cmd창에 Object.values(temp1)를 입력하면 값을 가져올 수 있는데 타입을 가져오는 코드를 작성해보자. (array의 value 값을 받아서 해당하는 type을 return)

Object.values(temp1).map(v=> typeof v).join()

7. 동일하게 6의 코드를 복붙하고, ctrl+D로 쉼표 제거, 엔터 후 잘라낸 코드를 5의 코드에 alt+shift+로 재선택하여 붙여주면 끝

✍5.7 Nested Routes part One

Nested router : route 안에 있는 또 다른 route

강의내용과 다르게, V6에서는 nested routes를 구현하는 방법에는 두가지가 있다.

✅1. 부모 route의 path 마지막에 /*를 적어 명시적으로 이 route의 내부에서 nested route가 render 될 수 있음을 표시하고 자식 route를 부모 route의 element 내부에 작성하는 방법
상대경로도 지원하기 때문에 path="chart"로 써도 제대로 동작한다.

//Router.tsx
<Route path="/:coinId/*" element={<Coin />} />

//Coin.tsx
<Routes>
	<Route path="price" element={<Price />} />
	<Route path="chart" element={<Chart />} />
</Routes>

✅2. 자식 route를 부모 element의 내부가 아닌 route 내부에 작성하는 방법

Router.tsx
<Routes>
	<Route path="/" element={<Coins />} />
	<Route path="/:coinId" element={<Coin />}>
		<Route path="chart" element={<Chart />} />
		<Route path="price" element={<Price />} 
    </Route>
</Routes>

Route를 설정하고, Coin.tsx에서 원하는 곳에 <Outlet />을 작성해주면 된다.

✍5.8 Nested Routes part Two

<Link to={`/${coinId}/chart`}>Chart</Link>
<Link to={`/${coinId}/price`}>Price</Link>

//동일한 코드
<Link to="chart">Chart</Link>
<Link to="price">Price</Link>

useRouteMatch 내가 특정한 URL에 있는지 여부를 알려준다.

V6에서는 useRouteMatch()가 사라지고 useMatch() 를 이용한다. 만약 특정한 URL에 있으면 Object를 반환하고, 아니면 null을 반환한다.

profile
뭐든지 난 열심히 하지

0개의 댓글