so woon!

[STYLED COMPONENTS] Recoil을 사용하지 않고 darkTheme, lightTheme 만들기 본문

Styled Components/개념정리

[STYLED COMPONENTS] Recoil을 사용하지 않고 darkTheme, lightTheme 만들기

xowoony 2023. 4. 14. 14:58

학습일 : 2023. 04. 14


 Recoil을 사용하지 않고 만드는 버전을 알아보자
Recoil 없이 다크모드/라이트모드 스위치를 구현하기 위해서는

 


<index.tsx>
기존에 index.tsx에 있는 ThemeProvider를 App.tsx로 옮긴다.

(옮기는 이유는 어플리케이션의 state에 기반하여 바꾸기 위해서임)


이동 전

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);

root.render(
  <QueryClientProvider client={queryClient}>
    <ThemeProvider theme={darkTheme}>
      <App />
    </ThemeProvider>
  </QueryClientProvider>
);



이동 후

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);

root.render(
  <QueryClientProvider client={queryClient}>
      <App />
  </QueryClientProvider>
);


<App.tsx>
이동 전

function App() {
  return (
    <>
      <GlobalStyle />
      <Router />
      <ReactQueryDevtools initialIsOpen={true} />
    </>
  );
}

export default App;



이동 후

import { ThemeProvider, createGlobalStyle } from "styled-components";
import { darkTheme, lightTheme } from "./theme"; // import
function App() {
  return (
    <>
<ThemeProvider theme={darkTheme}>
      <GlobalStyle />
      <Router />
      <ReactQueryDevtools initialIsOpen={true} />
      </ThemeProvider>
    </>
  );
}

export default App;




이로써 theme을 render 하는 ThemeProvider를 index.tsx에서 App component로 가져오게 되었다.


<theme.ts>
darkTheme과 lightTheme을 작성해준다.

import { DefaultTheme } from "styled-components";

export const darkTheme: DefaultTheme = {
  bgColor: "rgb(62 62 45)",
  textColor: "#f5f6fa",
  accentColor: "#e1b12c",
  boxColor:  "#2b281b"
}

export const lightTheme: DefaultTheme = {
  bgColor: "#c5c4b8",
  textColor: "black",
  accentColor: "#e1b12c",
  boxColor:  "rgb(173 167 141)"
};



<App.tsx>
darkTheme, lightTheme을 import 해준다. (난 아까 이미 해줬음)
그리고 ThemeProvider에 theme prop으로 삼항연산자를 써줌

import { darkTheme, lightTheme } from "./theme";

function App() {
  const [isDark, setIsDark] = useState(false);
  return (
    <>
      <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
        <GlobalStyle />
        <Router />
        <ReactQueryDevtools initialIsOpen={true} />
      </ThemeProvider>
    </>
  );
}

export default App;



이제 isDark를 true나 false로 toggle하는 function을 만들도록 한다.

 


<App.tsx>
setState function을 사용할 때 두가지 옵션이 있다. (참고)
1. const toggleDark = () => setIsDark(true);   그냥 이렇게 value를 보내거나
2. const toggleDark = () => setIsDark();    value 대신 function을 보내거나.

이 function은 첫번째 argument로 현재의 state를 가짐.

 


2. 를 사용 - 현재를 current로 두고 그 반대를 return 하도록 만든다.
isDark가 true이면 false를 return 하고, false이면 true를 return하게 된다.

  const toggleDark = () => setIsDark((current) => !current);




button 을 만들어 주고 onClick으로 toggleDark를 준다.
그럼 클릭시 state가 바뀌고 theme이 바뀌게 되어서 다크모드로 전환된다.


   

  <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
        <GlobalStyle />
        <Router />
        <ReactQueryDevtools initialIsOpen={true} />
        <button onClick={toggleDark}>테마 변경</button>
    </ThemeProvider>





<App.tsx>
전체 코드

function App() {
  const [isDark, setIsDark] = useState(false);
  const toggleDark = () => setIsDark((current) => !current);
  return (
    <>
      <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
        <GlobalStyle />
        <Router />
        <ReactQueryDevtools initialIsOpen={true} />
        <button onClick={toggleDark}>테마 변경</button>
      </ThemeProvider>
    </>
  );
}

export default App;




실행결과
클릭시 다크모드, 라이트모드로 바뀌는 것을 확인할 수 있다.

 

 

 


총 정리

 


1. App.tsx
function 을 Router 로 보냄

import { ThemeProvider, createGlobalStyle } from "styled-components";
import Router from "./Router";
import { ReactQueryDevtools } from "react-query/devtools";
import { darkTheme, lightTheme } from "./theme";
import { useState } from "react";

function App() {
  const [isDark, setIsDark] = useState(false);
  const toggleDark = () => setIsDark((current) => !current);
  return (
    <>
      <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
        <GlobalStyle />
        <Router toggleDark={toggleDark} />
        <ReactQueryDevtools initialIsOpen={true} />
      </ThemeProvider>
    </>
  );
}

export default App;





2. Router.tsx
그다음 Router에서 Coins로 보냄

import { BrowserRouter, Routes, Route } from "react-router-dom";
import Coins from "./routes/Coins";
import Coin from "./routes/Coin";

interface IRouterProps {
  toggleDark: () => void;
}

function Router({ toggleDark }: IRouterProps) {
  return (
    <BrowserRouter basename={process.env.PUBLIC_URL}>
      <Routes>
        <Route path={`/`} element={<Coins toggleDark={toggleDark} />} />
        <Route path="/:coinId/*" element={<Coin />} />
      </Routes>
    </BrowserRouter>
  );
}
export default Router;






3. Coins.tsx
그러고 나서야 Coins에서 이 function을 가지게 된다.

import { Link } from "react-router-dom";
import styled from "styled-components";
import { useQuery } from "react-query";
import { fetchCoins } from "../api";
import { Helmet } from "react-helmet";

interface ICoinsProps {
  toggleDark: () => void;
}

function Coins({toggleDark}:ICoinsProps) {
  // useQuery를 통해 Coins 를 fetch
  const { isLoading, data } = useQuery<ICoin[]>("allCoins", fetchCoins);
  return (
    <Container>
      <Helmet>
        <title>Thorn Coin</title>
      </Helmet>
      <Header>
        <Link to={"/"}>
          <Title>Thorn Coin</Title>
        </Link>
        <SubTitle>Grab Your Own Coin!</SubTitle>
        <button onClick={toggleDark}>테마 변경</button>
      </Header>
      {isLoading ? (
        <Loader>로딩중입니다...</Loader>
      ) : (
        <CoinsList>
          {data?.slice(0, 100).map((coin) => (
            <Coin key={coin.id}>
              <Link to={`/${coin.id}`} state={coin}>
                <Img
                  src={` https://cryptocurrencyliveprices.com/img/$ {coin.id}.png`}
                  alt=""
                />
                {coin.name}
              </Link>
            </Coin>
          ))}
        </CoinsList>
      )}
    </Container>
  );
}

export default Coins;

 

 

 

 

Comments