๐ก TIL 20230814
๋ฆฌ์กํธ ํ๋ก์ ํธ๋ฅผ ๋น๋ํ๋ฉด์ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋น์ฐํ๊ฒ๋(?) Redux๋ง ์จ๋ดค์๋ค. ํ์ง๋ง ์ธ์์ ๋น์ฐํ ๊ฒ์ ์๋ ๋ฒ.. Recoil, Zustand, Jotai ๋ฑ ๋ค๋ฅธ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์จ๋ณด๊ณ ์ถ๋ค๋ ์๊ฐ์ ๋จผ์ Recoil๋ถํฐ ์ค์นํด์ ์ฌ์ฉํด๋ณด๊ฒ ๋์๋ค.
1. Recoil์ด๋?
Recoil์ ํ์ด์ค๋ถ์ด ๋ง๋ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค. React ์ ์ฉ์ผ๋ก ๋์จ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ ๋งํผ ๋ฆฌ์กํธ์์ ์ต์ ํ๋์ด ์๋ํ๋ค.
์๋๋ Recoil ๊ณต์ ํํ์ด์ง์์ ์๊ฐํ๋ Recoil์ ํน์ง์ธ๋ฐ ์ค๋ช ์ด ๋ญ๊ฐ ๊ท์ฝ๋ค.
๋ฆฌ์กํธ ๊ณต์ ์ ํ๋ธ์์ ์ค๋ช ํ๋ Atom์ ๊ฐ๋ ๋์ด๋ค. redux์์๋ store๋ผ๋ ์ค์ ์ํ ๊ด๋ฆฌ์์ ๋ด์๋๊ณ ๊ด๋ฆฌํ๋ ๊ฐ๋ ์ด์๋ค๋ฉด, ๋ฆฌ์ฝ์ผ์์๋ ๋ญ๊ฐ ๊ณต์ค์ ๋ ๋ค๋๋ literally ์์๋ค์ ๊ฐ๋ ๊ฐ์์ ๊ท์ฝ๋ค.
์ํผ, ์ด atom๋ค์ ์ด๋ ์ปดํฌ๋ํธ์ ํ์ ๋์ด ์์ง ์๊ณ ๊ณต์ค ์ด๋๊ฐ์ ๋ ์๊ณ , atom ์ค ํ๋๊ฐ ํ์ํ๋ค๋ฉด ํด๋น ์ปดํฌ๋ํธ์์ ๊ณต์ค์ ๋ ์๋ atom๋ค ์ค ํ์ํ atom์ ๊ฐ์ ธ๋ค ์ฐ๋ ๊ฐ๋ ์ด๋ผ๊ณ ์ดํดํ๋ฉด ๋๋ค.
2. ์ธํ
๋ค๋ฅธ ์ํ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๊ทธ๋ฌํ๋ฏ์ด, ์ค์น๋ฅผ ํ๊ณ ๋ฃจํธ ์ปดํฌ๋ํธ์์ ๋ช ๊ฐ์ง ์ค์ ์ ํด์ฃผ์ด์ผ ํ๋ค.
1) ์ค์น
์๋ฌด ์๊ฐ ์์ด yarn add recoil๋ง ํด๋๊ณ ์ฌ์ฉํ๋๋ฐ ์๊พธ ์๋ฌ๊ฐ ๋์ ..์ค๋ง(???) ํ๋๋ฐ ํ์ ์คํฌ๋ฆฝํธ์์๋ @types/recoil๋ ํจ๊ป ์ค์นํด์ฃผ์ด์ผ ํ๋ค.
yarn add recoil @types/recoil
2) index.tsx
- ๋ฃจํธ ์ปดํฌ๋ํธ๋ฅผ <RecoilRoot></RecoilRoot>๋ก ๊ฐ์ธ์ฃผ์ด์ผ ํ๋ค.
import React from 'react';
import ReactDOM from 'react-dom/client';
import { QueryClient, QueryClientProvider } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools';
import { RecoilRoot } from 'recoil';
import App from './App';
const queryClient = new QueryClient();
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<RecoilRoot>
<QueryClientProvider client={queryClient}>
<App />
<ReactQueryDevtools initialIsOpen={true} />
</QueryClientProvider>
</RecoilRoot>
</React.StrictMode>
);
Recoil์ ์ฌ์ฉํ ์ค๋น๋ ๋๋ฌ๋ค. ์๋๋ถํฐ๋ ๋คํฌ๋ชจ๋ ์ํ๊ด๋ฆฌ ์์๋ก recoil ์ฌ์ฉ๋ฒ์ ์ ๋ฆฌํ๋ ค๊ณ ํ๋ค.
3) atoms.ts
- Atom์ state์ ์ผ๋ถ๋ฅผ ๋ํ๋ธ๋ค.
- Atom๋ค์ <RecoilRoot></RecoilRoot>๋ก ๊ฐ์ธ์ง ์ด๋ ์ปดํฌ๋ํธ์์๋ ์ฝ๊ณ ์ธ ์ ์๋ค.
- atom์ ๊ฐ์ ์ฝ๋ ์ปดํฌ๋ํธ๋ค์ ์๋ฌต์ ์ผ๋ก atom์ ๊ตฌ๋ ํ๋ค. ๋ฐ๋ผ์ atom์ ์ด๋ค ๋ณํ๊ฐ ์์ผ๋ฉด ๊ทธ atom์ ๊ตฌ๋ ํ๋ ๋ชจ๋ ์ปดํฌ๋ํธ๊ฐ ์ฌ๋ ๋๋ง๋๋ ๊ฒฐ๊ณผ๊ฐ ๋ฐ์ํ๋ค.
- atom์ ๊ณ ์ ํ key๋ฅผ ์ฃผ๊ณ , ๊ธฐ๋ณธ๊ฐ(redux์ initialState ๊ฐ๋ )์ธ default๊ฐ์ ์ค์ ํ ์ ์๋ค.
import { atom } from "recoil";
export const isDarkAtom = atom({
key: "isDark",
default: false,
});
3. ์ฌ์ฉ ๋ฐฉ๋ฒ
React๋ฅผ ์ํด ๋ง๋ค์ด์ง ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ ๊ทธ๋ฐ์ง, ์ฌ์ฉ๋ฐฉ๋ฒ์ด ๋์ฒด๋ก useState ํ ์ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๋น์ทํ๋ค.
1) useRecoilValue()
- ์ปดํฌ๋ํธ์์ atom์ ์ฝ๊ธฐ ์ํด useRecoilValue() ํ ์ ์ฌ์ฉํ์ฌ ์๋์ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ฑํ๋ฉด ๋๋ค.
- useRecoilValue(์์๋ Atom์ ๋ฃ์ด์ค๋ค)
import { ThemeProvider } from 'styled-components';
import { darkTheme, lightTheme } from './styles/theme';
import GlobalStyle from "./styles/GlobalStyle";
import Router from "./routes/Router";
import { useRecoilValue, useSetRecoilState } from "recoil";
import { isDarkAtom } from './recoil/atoms';
import styled from "styled-components";
import ToggleButton from "react-dark-mode-toggle";
const App = () => {
const isDark = useRecoilValue(isDarkAtom); // ์ค์ ํด์ค atom ๊ฐ์ ธ์ค๊ธฐ
const toggleDarkAtom = () => setDarkAtom(prev => !prev)
return (
<>
<ThemeProvider theme={isDark ? darkTheme : lightTheme}>
<GlobalStyle />
<DarkModeToggleBtn
checked={isDark}
size={50}
speed={1.5}
/>
<Router />
</ThemeProvider>
</>
);
};
export default App;
const DarkModeToggleBtn = styled(ToggleButton)`
position: absolute;
top: 3vh;
right: 3%;
`
2) useSetRecoilState()
- ์ด์ ํ ๊ธ ๋ฒํผ์ ๋๋ฅผ ๋, ์ด atom์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๊ธฐ ์ํด์ useSetRecoilState()ํ ์ ์ฌ์ฉํ์ฌ setter ํจ์๋ฅผ ๋ง๋ค์ด์ฃผ๋ฉด ๋๋ค.
- useSetRecoilState()๋ ๋งค๊ฐ๋ณ์๋ก atom์ ๋ฐ๊ณ , atom์ ๋ณ๊ฒฝํ๋ ํจ์๋ฅผ ๋ฐํํ๋ค.
- React์ ์ผ๋ฐ์ ์ธ setState ํจ์์ ๊ฐ์ ์๋ฆฌ๋ก ์๋ํ๋ค๊ณ ๋ณผ ์ ์๋ค.
import { ThemeProvider } from 'styled-components';
import { darkTheme, lightTheme } from './styles/theme';
import GlobalStyle from "./styles/GlobalStyle";
import Router from "./routes/Router";
import { useRecoilValue, useSetRecoilState } from "recoil";
import { isDarkAtom } from './recoil/atoms';
import styled from "styled-components";
import ToggleButton from "react-dark-mode-toggle";
const App = () => {
const isDark = useRecoilValue(isDarkAtom);
const setDarkAtom = useSetRecoilState(isDarkAtom); // setter ํจ์
const toggleDarkAtom = () => setDarkAtom(prev => !prev) // setter ํจ์๋ฅผ ์ด์ฉํ์ฌ ํ ๊ธํจ์ ์ ์
return (
<>
<ThemeProvider theme={isDark ? darkTheme : lightTheme}>
<GlobalStyle />
<DarkModeToggleBtn
onChange={toggleDarkAtom}
checked={isDark}
size={50}
speed={1.5}
/>
<Router />
</ThemeProvider>
</>
);
};
export default App;
const DarkModeToggleBtn = styled(ToggleButton)`
position: absolute;
top: 3vh;
right: 3%;
`
์ฐธ๊ณ ์ฌ์ดํธ
Recoil ๊ณต์ ํ๊ตญ์ด ๋ฌธ์