## Create Global Style
- 전체의 Element의 Style을 적용하고 싶을 때 사용한다.
- 보통 `Reset Style`이나 `Font`를 설정할 때 많이 사용한다.
```jsx
import styled, { createGlobalStyle } from 'styled-components';
const GlobalStyle = createGlobalStyle`
/*Reset*/
`
function App() {
return (
<>
<GlobalStyle />
<Container>
<RouterProvider router={router} />
</Container>
</>
);
```
- padding을 a태그 안에 넣어주면서 유저 친화적으로 스타일링함
```jsx
const Coin = styled.li`
background-color: white;
color: ${props => props.theme.bgColor};
margin-bottom: 10px;
padding: 20px;
border-radius: 15px;
a {
display: flex;
align-items: center;
padding: 20px;
transition: color 0.2s ease-in;
}
&:hover {
a {
color: ${props => props.theme.accentColor};
}
}
`;
```
- () => () 이런식으로 함수를 쓰면 함수를 정의하지 않고 즉시 사용 가능하다.
```jsx
useEffect(() => {
(async () => {
const response = await fetch("https://api.coinpaprika.com/v1/coins");
})();
}, []);
```
## Link를 사용해 비하인드 씬으로 값 전달하기
```jsx
<CoinsList>
{coins.map((coin) => (
<Coin key={coin.id}>
<Link to={`/${coin.id}`} state={{ name: coin.name }}>
<Img
src={`https://cryptocurrencyliveprices.com/img/${coin.id}.png`}
alt={coin.name}
width="35"
height="35"
/>{coin.name} →</Link>
</Coin>
))}
</CoinsList>
```
- 이렇게 전달한 state는 useLocation을 통해 얻을 수 있다.
```jsx
interface RouterState {
name: string;
}
function Coin() {
const { coinId } = useParams<keyof Params>();
const [loading, setLoading] = useState(true);
console.log(coinId);
const location = useLocation();
const name = location.state as RouterState;
return (
<Container>
<Header>
<Title>코인 {coinId}</Title>
</Header>
{loading ? (
<Loader>Loading...</Loader>
) : null}
</Container>
);
}
```
- 하지만 이러한 방식은 이전 페이지를 반드시 방문한 다음 이동되어야 된다.
- 그래서 만약 URL를 통해 직접 이동하는 경우를 대비해 조건을 걸어주는게 좋다.
## API에서 얻은 데이터들의 Type(Interface)을 쉽게 정하는 방법
- log를 통해 데이터를 본다.
- 해당 데이터를 Store as global variable를 통해 변수로 저장한다.
![[F12 Img.png]]
- 해당 변수에 `Object.keys(변수이름).join()`을 통해 각 Object의 `key` 값을 한 번에 파악할 수 있다.
- 해당 변수에 `Object.value(변수이름).map(v => typeof v).join()`을 통해 각 Object의 `value`의 `type`을 한 번에 파악할 수 있다.
- (복사 붙여넣기, Ctrl + D로 ,마다 커서를 놓고 지우고 설정하기)
## useMatch
- 현재 위치를 기준으로 지정된 경로에 대한 일치 데이터를 반환합니다.
- 해당 경로가 일치하면 Object를 출력하고 아니면 Null을 가진다.
matchPath() : matchPath는 URL 경로 이름에 대해 경로 패턴을 일치시키고 일치에 대한 정보를 반환합니다.
## React-Query
- 참고로 최신 버전의 React Quer는 @tanstack/react-query로 마이그레이션되었으므로, 밑의 명령어를 통해 설치하면 된다. (import 구문도 수정해야함)
```shell
npm install @tanstack/react-query
```
- Import 구문
```jsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
```
- React-Query에서 fetcher function은 반드시 json data의 promise를 반환해야 한다.
- useQuery라는 hook이 fetcher함수를 불러오고 fetcher함수가 끝이 나면 useQuery의 isLoading의 값이 True로 바꾸고 data에 API에서 나온 값을 담는다.
- 데이터를 GET 하기 위한 `useQuery` api 이며, POST, UPDATE는 `useMutaion`을 사용한다.
- React-Query는 데이터를 캐시에 저장해주기 때문에
- 기존 방식
```jsx
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, 100));
setLoading(false);
})();
}, []);
```
- React-Query 방식
```jsx
import { useQuery } from "@tanstack/react-query";
import { fetchCoins } from "../api";
// useQuery(Coins.tsx)
const { isLoading, data } = useQuery({
queryKey: ["allCoins"],
queryFn: fetchCoins
});
// fetcher function(api.tsx)
export async function fetchCoins() {
const response = await fetch("https://api.coinpaprika.com/v1/coins");
const json = await response.json();
return json.slice(0, 100);
}
```
## React Query devTools
- React Query로부터 온 정보들을 볼 수 있다.
```shell
npm install @tanstack/react-query-devtools
```
- React Query 참고 자료
- https://velog.io/@tlatjdgh3778/React-Query%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A0%95%EB%A6%AC
- https://menduck.tistory.com/entry/%F0%9F%9A%A8%EC%9D%91%EA%B8%89%EC%8B%A4-%EC%95%8C%EB%A6%AC%EB%AF%B8-React-query%EC%97%90%EC%84%9C-error-%EC%B2%98%EB%A6%AC
- React Query랑 Axios랑 다른 점
- https://velog.io/@rsoy2918/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%BF%BC%EB%A6%ACReact-Query%EC%99%80-axios
>목적과 기능:
> - axios: 주로 서버와의 데이터 통신을 위해 사용됩니다. RESTful API를 호출하고 응답 데이터를 받아오는 데 중점을 둡니다.
> - 리액트 쿼리: 리액트 애플리케이션에서 데이터를 가져오고 관리하는 데 사용됩니다. 여러 종류의 데이터 요청을 지원하고, 캐싱, 상태 관리, 에러 핸들링 등 데이터 관리를 위한 다양한 기능을 제공합니다.
> 데이터 관리 방식:
> - axios: 데이터 요청과 응답은 Promise 기반의 방식으로 처리됩니다. 콜백을 사용하거나 async/await와 같은 비동기 패턴을 사용합니다.
> - 리액트 쿼리: 데이터 요청과 상태 관리는 훅(Hook) 기반으로 처리됩니다. useQuery, useMutation, useQueryClient 등의 훅을 제공하여 데이터 요청과 상태 업데이트를 간단하게 처리할 수 있습니다.
> 데이터 캐싱 및 상태 관리:
> - axios: 데이터 요청과 응답은 각각 독립적으로 이루어집니다. 따라서 데이터의 캐싱과 상태 관리는 개발자가 직접 처리해야 합니다.
> - 리액트 쿼리: 데이터 요청과 상태 관리를 통합적으로 처리합니다. 캐싱 기능을 제공하여 중복 요청을 효율적으로 처리하고, 상태 관리를 통해 컴포넌트의 상태를 업데이트하면 쿼리가 자동으로 다시 호출되도록 설정할 수 있습니다.
- 두 라이브러리는 각각의 장점과 특징에 따라 상황에 맞게 사용하면 된다.
- axios는 주로 서버와의 통신에 사용되며, 리액트 쿼리는 리액트 애플리케이션에서 데이터를 효과적으로 관리하기 위해 사용된다. 따라서 데이터 요청만을 고려한다면 axios를 사용하는 것이 일반적이지만, 리액트 애플리케이션에서 데이터를 관리하는 데 추가적인 기능이 필요하다면 리액트 쿼리를 사용하는 것이 유용할 수 있다.
## apexcharts - Date 시각화 라이브러리
- 공식 문서(https://www.apexcharts.com/)
```shell
npm install --save react-apexcharts apexcharts
```
```jsx
import ApexChart from "react-apexcharts";
<ApexChart
type="line"
series={[{
name: "price",
data: data?.map((price) => price.close) as number[]
},]}
options={{
chart: {
height: 500,
width: 500,
toolbar: {
show: false,
},
background: "transparent"
},
theme: {
mode: "dark",
},
stroke: {
curve: "smooth",
width: 4,
},
grid: {
show: false,
},
yaxis: {
show: false,
},
xaxis: {
labels: {
show: false,
},
axisBorder: { show: false },
axisTicks: {
show: false,
},
type: "datetime",
categories: data?.map((price) => price.time_close) as string[],
},
fill: {
type: "gradient",
gradient: {
gradientToColors: ["#0be881"],
stops: [0, 100],
},
},
tooltip: {
y: {
formatter: (value) => `${value.toFixed(2)}`,
},
},
}}
/>
```
## Helmet
- React page의 head 제목을 바꿀 수 있다.
```shell
npm i react-helmet-async
```
- App()에서 HelmetProvider로 감싸고
- 각 Component에서 helmet을 통해 불러오면 된다.
```jsx
import { HelmetProvider } from 'react-helmet-async';
function App() {
return (
<>
<HelmetProvider>
<GlobalStyle />
<Container>
<RouterProvider router={router} />
</Container>
</HelmetProvider>
<ReactQueryDevtools initialIsOpen={true} />
</>
);
}
```
```jsx
import { Helmet } from "react-helmet-async";
<Helmet>
<title>{state?.name ? state.name : loading ? "Loading..." : infoData?.name}</title>
</Helmet>
```
- 버전 충돌 발생
```shell
--legacy-peer-deps 옵션을 사용하여 설치:
npm install react-helmet-async --legacy-peer-deps
```