230108.til

Universe·2023년 1월 7일
0
post-custom-banner

서론

노마드 코더 첫번째 프로젝트 시작







Crypto Tracker

  1. 프로젝트 파일 구조
/ -> All coins
/:id -> /btc -> Coin Detail
	(nested)
	/btc/information
	/btc/chart
  1. npm i
$npx create-react-app "이름" —template typescript
$npm i --save react react-dom typescript
$npm i --save-dev @types/react @types/react-dom @types/node
$npm i react-router-dom@5.3.0
	(강의가 이전버전의 router dom 으로 제작되어 기존 버전을 사용)
$npm i react-query

react-router 를 6버전만 써봤기에 어떤점이 달라졌는지 알아보고 싶었고,

나중에 router 6버전으로 고쳐봐도 재밌을 것 같다.

  1. 프로젝트를 시작하기 전에 알아야 할 사항들
tsconfig.json 파일을 생성하려면
tsc --init

CRA 태그들을 사용하려면 tsconfig.json 에서
"jsx":"react-jsx"
로 변경해주어야 함

가장먼저 index.tsx 에서
const root = ReactDOM.createRoot(document.getElementById("root"));
이 부분을
const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
이렇게 바꿔주어야 함
  1. 심지어 useParams 에서도…
const Coin = () => {
  const { coinId } = useParams();
  return <h1>Coin : {coinId}</h1>;
};

위의 구문은 js에서는 아무런 문제가 없다.

그러나 우리의 귀여운 ts 에서는

Property 'coinId' does not exist on type '{}'

이라는 에러를 띄운다.

ts가 봤을 때 해당 객체에 들어간 object 내부의 값이 어떤 type 인지 모르기 때문이다.

interface RouteParams {
  coinId: string;
}

const Coin = () => {
  const { coinId } = useParams<RouteParams>();
  return <h1>Coin : {coinId}</h1>;
};

이렇게 useParams 로 들어올 object의 type을 명시해주어야만 사용이 가능하다.

  1. createGlobalStyle

전역으로 사용할 global style을 적용해보자.

// ./styles/GlobalStyle.tsx

import { createGlobalStyle } from "styled-components";
export const GlobalStyle = createGlobalStyle`
	...
`

전역적으로 공통적인 속성,

흔히 사용하는 border:0, padding:0, box-sizing:border-box 같은 스타일을

index.css 가 아닌 styled-components 로 적용할 수 있는 키워드.

  1. tsx + ThemeProvider

첫째, 전역에서 사용할 theme 파일을 만들어준다.

// ./style/theme.tsx

import { DefaultTheme } from "styled-components";

export const theme: DefaultTheme = {
  bgColor: "#2f3640",
  textColor: "#f5f6fa",
  accentColor: "#44bd32",
};

둘째, 적용할 대상을 감싸준다. index.tsx 에서 찾으면 됨.

// ./index.tsx
import { ThemeProvider } from "styled-components";
import { theme } from "./styles/theme";

root.render(
	<ThemeProvider theme={theme}>
		<App />
	</ThemeProvider>
)

가장 중요한 셋째, *.d.ts 파일로 전역타입 추론을 해준다.

// ./styles/styled.d.ts

import "styled-components";

declare module "styled-components" {
  export interface DefaultTheme {
    bgColor: string;
    textColor: string;
    accentColor: string;
  }
}
&rarr; ===

해당 키워드로 화살표를 나타내줄 수 있다 !

  1. 즉시실행함수
useEffect(() => {
    (async () => {
      const response = await fetch("https://api.coinpaprika.com/v1/coins");
      const json = await response.json();
      setCoins(json.slice(0, 50));
    })();
  }, []);

이거 정말 많이 고민한 문제였는데,

useEffect 내에서 ()(); 같은 즉시실행 함수를 사용해

변수나 함수를 정의해주지 않아도 바로 실행하도록 설계할 수 있다.

  1. React Query 를 사용하지 않은 Loading page 구현
const Coins = () => {
	const [coins, setCoins] = useState<CoinInterface[]>([]);
  const [loading, setLoading] = useState(true);
  useEffect(() => {
    (async () => {
      const response = await fetch("https://api.coinpaprika.com/v1/coins");
      const json = await response.json();
      setCoins(json.slice(0, 50));
      setLoading(false);
    })();
  }, []);

  return (
    <Container>
      <Header>
        <Title>Coins</Title>
      </Header>
      {loading ? (
        <Loading>Loading...</Loading>
      ) : (
        <CoinsList>
          {coins.map((coin) => (
            <Coin key={coin.id}>
              <Link to={`/${coin.id}`}>{coin.name} &rarr;</Link>
            </Coin>
          ))}
        </CoinsList>
      )}
    </Container>
  );
};

페이지가 렌더링 될 때 API fetch 요청을 해서 가져온 데이터를 state에 저장하여 mapping 하는 로직

Loading 의 boolean 값이 true 일 때 로딩 페이지를 보여주고,

API fetch 요청이 끝나면 Loading state를 false로 바꾸어 불러온 데이터를 보여준다.

위 로직에는 아주 치명적인 단점이 있다.

페이지를 오갈 때 마다, 렌더링이 될 때마다 API 요청을 하여 데이터를 mapping 하는 로직을 재실행 한다는 것.

React Query 를 사용하면 그렇게 하지 않아도 데이터가 state에 남아있을 수 있나 ?







결론

타입스크립트 이 친구 정말정말 까다로워서 뭐 하나 그냥 넘어가는게 없다.
tsc init 을 해주어야 tsconfig.json 이 생기는 것도 마음에 들고,
직관적으로 너 틀렸어! 하고 말해주는게 너무 마음에 든다.
오류때문에 헤메긴 했지만 조금 더 친해지면 잘 지낼 수 있을 것 같은 친구다. 🥰
그것과 별개로 오랜만에 강의 보면서 소소하게 코딩하니까
힐링하는 느낌이 강하게 든다.
실전프로젝트 주간이라서 언제까지 이렇게 마음놓고 공부할 수는 없겠지만.. 🥲

profile
Always, we are friend 🧡
post-custom-banner

0개의 댓글