전역상태관리 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에 따라 버튼에 따라 버튼도 바뀌고 배경및색상도 바뀐다