Recoil: state management library. (cf. redux)
import { DefaultTheme } from "styled-components";
export const darkTheme: DefaultTheme = {
bgColor: "#2f3640",
textColor: "white",
accentColor: "#9c88ff",
cardBgColor: "transparent",
};
export const lightTheme: DefaultTheme = {
bgColor: "whitesmoke",
textColor: "black",
accentColor: "#9c88ff",
cardBgColor: "white",
};
function App() {
const [isDark, setIsDark] = useState(false);
const toggleDark = () => setIsDark((current) => !current);
return (
<>
<ThemeProvider theme={isDark ? darkTheme : lightTheme}>
<GlobalStyle />
<Router isDark={isDark} toggleDark={toggleDark} />
styled-component+TS로 작성한 theme은 다음과 같다.
두 개의 theme은 Coins.tsx 파일에서의 버튼 클릭으로 전환하도록 작성되어있다. 이를 Coin 페이지 안에서 중첩 라우팅 되어있는 Chart.tsx 속 ApexChart의 props에 반영하려고 한다.
현재 파일구조가 이러하기 때문에 Coin 페이지 안의 Chart에서 theme을 전환하기 위해서는 다음과 같은 단계를 거쳐야 한다.
아래는 function 전송의 예시. (오잉 boolean으로 Coin에 전송했네.. 둘 다 보면 될 것 같다.)
interface IRouterProps {
toggleDark: () => void;
//TS에서 function 전송은 이렇게 (parameter/return 없음)
isDark: boolean;
}
function Router({ toggleDark, isDark }: IRouterProps) {
return (
<BrowserRouter>
<Switch>
<Route path="/:coinId">
<Coin isDark={isDark} />
</Route>
<Route path="/">
<Coins toggleDark={toggleDark} />
딱 봐도 귀찮다.
이것은 state가 위치에 구애받기 때문이다.
위치에 상관없이 전역적으로 사용하는 state가 global state다.
Recoil에서는 이런 global state를 atom이라고 한다. Recoil Atom은 한 컴포넌트에 직접 연결되지 않기 때문에 어디서든 직접 access 해서 사용하면 된다.
key와 default값만이 필요하다.
import { atom } from "recoil";
export const isDarkAtom = atom({
key: "isDark",
default: true,
});
위에서 생성한 atom을 사용하기 위해서는 useRecoilValue를 사용하면 된다.
~
import { useRecoilValue } from "recoil";
import { isDarkAtom } from "./atoms";
~
function App() {
const isDark = useRecoilValue(isDarkAtom);
return (
<>
<ThemeProvider theme={isDark ? darkTheme : lightTheme}>
~
</ThemeProvider>
</>
);
}
setState와 같은 방식으로 사용한다. 아래는 theme을 전환하는 버튼이다.
const setDarkAtom = useSetRecoilState(isDarkAtom);
const toggleDarkAtom = () => setDarkAtom((prev) => !prev);
return(
~
<button onClick={toggleDarkAtom}>Toggle Mode</button>