
전역상태관리 Recoil 라이브러리를 사용해 간단하게 앱의 테마를 변경하는 작업을 해보고, 해당 내용을 적었습니다.
먼저 Recoil의 Atoms를 설정해 전역적으로 사용할 수 있도록 지정해야한다.
atom 객체의 필수값은 key와 default인데, key는 atom을 내부적으로 구별할 수 있게하는 역할을 하고, deafult는 useState에서의 초깃값과 같은 역할을 한다.📝 atoms/themeAtom.ts
import {atom} from "recoil";
export const themeAtom = atom({
key: "theme",
default: "light",
});
기본적으로 recoilAtoms는 앱 내부 최상단에서 RecoilRoot라는 컴포넌트를 공급해줘야 사용할 수 있다.
main.tsx의 React.StricMode 아래 RecoilRoot 컴포넌트를 공급했다.
import {RecoilRoot} from "recoil";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<RecoilRoot>
<App />
</RecoilRoot>
</React.StrictMode>
);
과정
ThemeToggleButton이라는 컴포넌트를 만들고,useRecoilState hook으로 만들어뒀던 atom을 가져와 사용했다useRecoilState는 useState와 모양이 아주 비슷해서 사용하기 쉬울듯하다.handleToggleTheme함수 내부에서 newTheme이라는 변수를 선언한 뒤, 삼항연산자로 버튼 클릭시 기본값으로 지정했던 theme이 light일땐 dark로, dark일땐 light로 토글되도록 구성했다setTheme 내부에 바뀐 newTheme을 넣음으로써 theme이 동적으로 업데이트 되도록 구성하였다.ThemeToggleButton 컴포넌트는 theme의 상태에 따라 react-icons라이브러리의 FiSun이나 FiMoon으로 조건부 렌더링된다themeAtom은 handleToggleTheme함수에 의해 값이 동적으로 변하는 상태가 되었다<function ThemeToggleButton() {
const [theme, setTheme] = useRecoilState(themeAtom);
const handleToggleTheme = () => {
const newTheme = theme === "light" ? "dark" : "light";
setTheme(newTheme);
localStorage.setItem("theme", newTheme);
};
/* 새로고침시에도 테마 유지하기 */
useLayoutEffect(() => {
const localStorageTheme = localStorage.getItem("theme");
if (localStorageTheme) {
setTheme(localStorageTheme);
}
}, [setTheme]);
return (
<button
type="button"
onClick={handleToggleTheme}
className="cursor-pointer pb-6 top-12 right-12 absolute">
{theme === "light" ? <FiSun size={30} /> : <FiMoon size={30} />}
</button>
);
}
이제 theme은 동적으로 값이 변하는 상태가 되었다
thmeToggleButton에 의해 theme이 토글됨과 동시에 앱 내부의 전체적인 색상도 바뀌어야한다.Container 컴포넌트에서 배경색상과 텍스트 색상을 theme에 의해 바뀌도록 삼항연산자로 구성하였다.import {ReactNode} from "react";
import {useRecoilValue} from "recoil";
import {themeAtom} from "../states/recoil/themeAtom";
interface IContainer {
children: ReactNode;
}
function Container({children}: IContainer) {
const theme = useRecoilValue(themeAtom);
const isRightTheme = theme === "light";
const lightThemeCSS = "bg-white text-[##1c1e21]";
const darkThemeCSS = "bg-[#18191a] text-[#f5f6f7]";
const themeCSS = isRightThem ? lightThemeCSS : darkThemeCSS;
return (
<>
<div
className={`flex py-12 w-full h-fit items-center justify-center flex-col p-12 mobile:p-6 ${themeCSS}`}>
{children}
</div>
</>
);
}
export default Container;
이제 ThemeToggleButton에 따라 버튼에 따라 버튼도 바뀌고 배경및색상도 바뀐다
