-> 보이지 않는 방식으로 데이터를 보내는 법
interface CoinInterface {
id: string;
name: string;
symbol: string;
rank: number;
is_new: boolean;
is_active: boolean;
type: string;
}
const [coins, setCoins] = useState<CoinInterface[]>([]);
-> coin으로된 array임을 알려주기
useEffect
: 특정 시기(시작, 끝, 변화할 때)에만 코드를 실행
useEffect(() => {
(async () => {
const response = fetch('https://api.coinpaprika.com/v1/coins');
const json = await (await response).json();
console.log(json);
})();
}, []);
엄청 많은 양의 데이터 가져옴 …
→ .slice
사용
setCoins(json.slice(0,100));
//100개만 가져오기
const [loading, setLoading] = useState(true);
{loading ? (
<Loader>Loading ... </Loader>
) : (
<CoinsList>
{coins.map((coin) => (
<Coin key={coin.id}>
<Link to={`/${coin.id}`}>{coin.name} →</Link>
</Coin>
))}
</CoinsList>
)}
coins → coin 이동시 가지고 있던 state 사라짐 → API re-fetch
https://coinicons-api.vercel.app
코인 아이콘 가져오기
<Img
src={`https://coinicons-api.vercel.app/api/icon/${coin.symbol.toLowerCase()}`}
/>
parameter를 이용해 URL에게 정보 넘기기
state 사용 (보이지 않는 방식으로 데이터를 보내는 법)
//Coins.tsx
<Link to={`/${coin.id}`} state={coin.name}>
+)
React Router 5버전
< Link to={{ pathname: "/home", state: state }} / >
React Router 6버전
< Link to="/home" state={state} / >
//Coin.tsx
interface RouteParams {
coinId: string;
}
const { coinId } = useParams<{ coinId: string }>();
<Title>코인 {coinId}</Title>
좀 더 멋진 방 법 !
react router DOM이 보내주는 location object에 접근
interface RouteState {
state:{
name: string;
};
}
const {state} = useLocation() as RouteState;
<Title>코인 {state.name}</Title>
coins 화면을 먼저 거치고 coin으로 들어오면 [state.name](http://state.name)
표시됨
바로 coin으로 들어오면 name → undefined
!
const response = fetch('https://api.coinpaprika.com/v1/${coinId}');
const json = await (await response).json();
->
const infoData = await (
await fetch(`https://api.coinpaprika.com/v1/${coinId}`)
).json();
const [info, setInfo] = useState({});
const [priceInfo, setPriceInfo] = useState({});
useEffect(() => {
(async () => {
const infoData = await (
await fetch(`https://api.coinpaprika.com/v1/${coinId}`)
).json();
const priceData = await (
await fetch(`https://api.coinpaprika.com/v1/${coinId}`)
).json();
setInfo(infoData);
setPriceInfo(priceData);
})();
}, []);
-> typescript는 info와 priceInfo를 빈 object로 인식한다 ^__^…
interface InfoData {
id: string;
name: string;
symbol: string;
rank: number;
is_new: boolean;
is_active: boolean;
type: string;
logo: string;
tags: ITag[];
team: object;
description: string;
message: string;
open_source: boolean;
started_at: string;
development_status: string;
hardware_wallet: boolean;
proof_type: string;
org_structure: string;
hash_algorithm: string;
links: object;
links_extended: object;
whitepaper: object;
first_data_at: string;
last_data_at: string;
}
interface PriceData {
id: string;
name: string;
symbol: string;
rank: number;
circulating_supply: number;
total_supply: number;
max_supply: number;
beta_value: number;
first_data_at: string;
last_updated: string;
quotes: {
USD: {
ath_date: string;
ath_price: number;
market_cap: number;
market_cap_change_24h: number;
percent_change_1h: number;
percent_change_1y: number;
percent_change_6h: number;
percent_change_7d: number;
percent_change_12h: number;
percent_change_15m: number;
percent_change_24h: number;
percent_change_30d: number;
percent_change_30m: number;
percent_from_price_ath: number;
price: number;
volume_24h: number;
volume_24h_change_24h: number;
};
};
}
const [info, setInfo] = useState<InfoData>();
const [priceInfo, setPriceInfo] = useState<PriceData>();
타입정의 해줫다 알아묵어라~
괄호 안에 아무 것도 안 넣으면 no dependency
: 컴포넌트의 시작에서만 실행
+) 괄호 안에 넣으면 바뀔 때마다 실행
지금 상황에서는 coinId가 컴포넌트 내에서는 변하지 않으므로 API request 한번만 실행
중첩된 라우터 (route 안에 있는 또 다른 route)
/*
를 적어 이 route의 내부에서 nested route가 render 될 수 있음을 표시하고 자식 route를 부모 route의 element 내부에 작성//Router.tsx
<Route path="/:coinId/*" element={<Coin/>}/>
//Coin.tsx
<Routes>
<Route path="chart" element={<Chart />} />
<Route path="price" element={<Price />} />
</Routes>
Routes가 상대경로도 지원하기 때문에 path="chart"
와 같이 써도 동작한다
//Router.tsx
<Route path="/:coinId" element={<Coin />} >
<Route path="chart" element={<Chart />} />
<Route path="price" element={<Price />} />
</Route>
//Coins.tsx
</CoinsList>
)}
<Outlet />
</Container>
자식 Route들이 어디에 render 될지 부모의 element안에 Outlet을 이용해 표시
(import 잊지 말기!)
react-router 6 이하 버전에서는 useReactMatch
특정한 URL에 있는지 여부를 알 수 있음
const priceMatch = useMatch('/:coinId/price');
해당 URL에 있으면 isExact: true
object를 보내줌 (없으면 null)
<Tab isActive={chartMatch !== null}>
<Link to={`/${coinId}/chart`}>Chart</Link>
</Tab>
null 이 아니면 해당 URL에 있다는 뜻!