728x90
npm install recoil
//index.tsx
import { RecoilRoot } from 'recoil';
<RecoilRoot>
</RecoilRoot>
이거추가한다.
그럼 이렇게 된다.
//index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { QueryClient, QueryClientProvider } from 'react-query';
import { RecoilRoot } from 'recoil';
const queryClient = new QueryClient();
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</RecoilRoot>
</React.StrictMode>
);
atoms.ts 파일 생성한다.
atom은 두가지를 요구하는데
첫번째는 key로, 이름인데 유일해야한다.
두번째는 기본값이다.
import {atom} from "recoil";
export const isDarkAtom = atom({
key: "isDark",
default: false,
})
이렇게하면 방울인 atom이 만들어진다.
이제 App과 chart를 이 atom에 연결해야한다.
일단 만들어진 atom을 쓰려면 useRecoilValue를 사용해야 한다.
import { useRecoilValue } from "recoil";
import { isDarkAtom } from './atoms';
const isDark = useRecoilValue(isDarkAtom)
<ThemeProvider theme={isDark ? darkTheme : lightTheme}>
이렇게 하면
어플리케이션이 isDarkAtom으로 연결되고, isDarkAtom의 기본값은 false이다.
//app.tsx
import React, { useState } from 'react';
import styled, { createGlobalStyle } from "styled-components";
import { ThemeProvider } from 'styled-components';
import { darkTheme, lightTheme } from './theme';
import Router from './Router';
import { ReactQueryDevtools } from "react-query/devtools";
import { useRecoilValue } from "recoil";
import { isDarkAtom } from './atoms';
const GlobalStyle = createGlobalStyle`
@import url('https://fonts.googleapis.com/css2?family=Hind&display=swap');
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, menu, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
main, menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, main, menu, nav, section {
display: block;
}
/* HTML5 hidden-attribute fix for newer browsers */
*[hidden] {
display: none;
}
body {
line-height: 1;
}
menu, ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
*{
box-sizing: border-box;
}
body {
font-family: 'Hind', sans-serif;
background-color: ${(props)=> props.theme.bgColor};
color: ${(props)=> props.theme.textColor}
}
a {
text-decoration: none;
color: inherit;
}
`;
function App() {
const isDark = useRecoilValue(isDarkAtom)
return (
<>
<ThemeProvider theme={isDark ? darkTheme : lightTheme}>
<GlobalStyle />
<Router/>
<ReactQueryDevtools initialIsOpen={true} />
</ThemeProvider>
</>
);
}
export default App;
value를 가져오는거 -> useRecoilValue
value를 수정하는거 -> useSetRecoilState
setter function은 value를 설정(set)하는 function이다.
coins.tsx 이거추가했다.
import { isDarkAtom } from "../atoms";
import { useSetRecoilState } from "recoil";
const setterFn = useSetRecoilState(isDarkAtom)
<button onClick={() => setterFn((prev) => !prev)}>Toggle Mode</button>
//coins.tsx
import styled from "styled-components";
import {Link} from "react-router-dom"
import { useEffect, useState } from "react";
import { useQuery } from "react-query";
import { fetchCoins } from "../api";
import { Helmet } from "react-helmet";
import { isDarkAtom } from "../atoms";
import { useSetRecoilState } from "recoil";
const Container = styled.div`
padding: 0px 20px;
max-width: 480px;
margin: 0 auto;
`;
const Header = styled.header`
height: 10vh;
display: flex;
justify-content: center;
align-items: center;
`;
const CoinsList = styled.ul``;
const Coin = styled.li`
background-color: white;
color: ${props => props.theme.textColor};
padding: 20px;
margin-bottom: 10px;
border-radius: 10px;
a {
display: flex;
align-items: center;
padding: 20px;
transition: color 0.4s ease-in;
}
&:hover {
a {
color: ${props => props.theme.accentColor}
}
}
`;
const Title = styled.h1`
font-size: 48px;
color: ${props => props.theme.accentColor}
`;
const Loader = styled.span`
text-align: center;
display: block;
`;
const Img = styled.img`
width: 35px;
height: 35px;
margin-right: 10px;
`;
interface CoinInterface {
id:string;
name: string;
symbol: string;
rank: number;
is_new: boolean;
is_active: boolean;
type: string;
}
function 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, 100))
setLoading(false);
})();
}, []);
console.log(coins) */
const setterFn = useSetRecoilState(isDarkAtom)
const { isLoading, data } = useQuery<CoinInterface[]>("allCoins", fetchCoins);
return <Container>
<Helmet>
<title>코인</title>
</Helmet>
<Header>
<Title>코인</Title>
<button onClick={() => setterFn((prev) => !prev)}>Toggle Mode</button>
</Header>
{isLoading ? (<Loader>Loading...</Loader>)
: (<CoinsList>
{data?.slice(0, 100).map(coin =>
<Coin key={coin.id}>
<Link to={`/${coin.id}`} state={coin.name}>
<Img
src={`https://coinicons-api.vercel.app/api/icon/${coin.symbol.toLowerCase()}`}
/>
{coin.name} →
</Link>
</Coin>)
}
</CoinsList>)}
</Container>
}
export default Coins;
728x90
'부트캠프교육중 > react' 카테고리의 다른 글
[React] Ts+eslint+prettier 기초셋팅설정 (0) | 2023.08.29 |
---|---|
[React] TypeScript + eslint + prettier 중 발생한 오류 해결 (0) | 2023.08.28 |
[React] Dark모드, Light모드 적용하기 (0) | 2023.08.27 |
[React] React query 적용 후 코드 (0) | 2023.08.26 |
[React] React query 적용하기 2 (0) | 2023.08.26 |