본문 바로가기
부트캠프교육중/react

[React] recoil적용하기

by 뭉지야 2023. 8. 27.
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} &rarr;
        </Link>
        </Coin>)
    }
    </CoinsList>)}
    </Container>
}
export default Coins;
728x90