동일한 state를 다른 components에서 사용해야 할 때, props 대신에 상태관리 라이브러리 recoil로 grobal state 버블(atom)을 생성해서 사용할 수 있다.
Recoil 시작하기 문서
https://recoiljs.org/ko/docs/introduction/getting-started/
npm install recoil명령어로 recoil을 install한다.RecoilRoot를 부모 트리에 넣어준다. app, index..등..// index.tsx
import { RecoilRoot } from "recoil";
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<RecoilRoot>
<App />
</RecoilRoot>
);
atom.ts를 생성한다. Atom은 상태(state)의 일부를 나타낸다.const textState = atom({
key: 'textState', // unique ID (with respect to other atoms/selectors)
default: '', // default value (aka initial value)
});
//atom.ts
import { atom } from "recoil";
export const isDarkModeAtom = atom({
key: "isDarkMode",
default: false,
});
useRecoilState() 으로 state(상태) 읽고 쓰기.useState와 비슷하게 state와 state함수 형태로 atom.ts의 state를 읽고 쓸 수 있다.//Footer.tsx
import { isDarkModeAtom } from "../atoms";
import { useRecoilState } from "recoil";
function Footer() {
const [isDarkMode, setDarkMode] = useRecoilState(isDarkModeAtom);
const toggleMode = () => {
setDarkMode((currentMode) => !currentMode);
};
return (
<Foot>
<ThemeBtn onClick={toggleMode}>
{isDarkMode ? "LightMode" : "DarkMode"}
</ThemeBtn>
</Foot>
)
}
혹은 useRecoilState 대신 useRecoilValue로 atom의 state 값을 사용만 하거나,
useSetRecoilState 함수로 값을 변경만도 할 수 있다.
const [isDarkMode, setDarkMode] = useRecoilState(isDarkModeAtom);
const isDarkMode = useRecoilValue(isDarkModeAtom);
const setDarkMode = useSetRecoilState(isDarkModeAtom);
ThemeProvider와 연결해서 atom state에 따라 테마를 변경할 수 있도록 darkmode/lightmode도 구현할 수 있다.//App.tsx
import { ThemeProvider } from "styled-components";
import { themeDark, themeLight } from "./theme";
import { useRecoilValue } from "recoil";
import { isDarkModeAtom } from "./atoms";
function App() {
// recoil(Atom state), DarkMode/LightMode
const isDarkMode = useRecoilValue(isDarkModeAtom);
return (
<>
<ThemeProvider theme={isDarkMode ? themeDark : themeLight}>
<Router />
</ThemeProvider>
</>
);
}
ThemeProvider 사용하여 darkMode/lightMode 구현은 아래 styled-components 참고[React] TS + Theme(styled-components)
https://velog.io/@mangosteen977/React-TS-Temestyled-components
6-1. get
get: ({
get: GetRecoilValue;
getCallback: GetCallback;
})
selector get을 이용해 atom state를 selector로 가져올 수 있다.
//atoms.ts
export const toDoSelector = selector({
key: "toDoSelector",
get: ({ get }) => {
const toDos = get(toDoStateAtom);
// toDoStateAtom의 state값 가져옴
return [
toDos.filter((toDo) => toDo.category == "TO_DO"),
toDos.filter((toDo) => toDo.category == "DOING"),
toDos.filter((toDo) => toDo.category == "DONE"),
];
},
});
selector에서 수정되어 파생 된 state는 useRecoilValue() 훅을 이용해 읽을 수 있다.
import { useRecoilValue } from "recoil";
import { toDoSelector } from "../atom";
function ToDoList() {
const [todo, doing, done] = useRecoilValue(toDoSelector);
6-2. set
set: ({
set: SetRecoilState;
//set(RecoilState명, 설정할 값) :해당 State의 값을 설정
get: GetRecoilValue;
// get(RecoilState명) : 해당 State의 값을 가져옴
reset: ResetRecoilState;
}, newValue)
// newValue : Selector의 set()함수를 사용해 받은 값
set(값을 변경할 atomState명, 값)의 형태로 atom state의 값을 설정할 수 있다.
export const hoursSelectorAtom = selector<number>({
key: "hours",
set: ({ set }) => {
set(minutesStateAtom, 60);
},
});
useRecoilState훅의 SetterOrUpdater()로 값을 반환하면, atoms.ts의 set함수에서 set:(newValue)로 값을 받을 수 있다.
// app.tsx
const [hours, setHours] = useRecoilState(hoursSelectorAtom);
const onHoursChange = (event: React.FormEvent<HTMLInputElement>) => {
setHours(event.currentTarget.value);
};
// atoms.ts
export const hoursSelectorAtom = selector<number>({
key: "hours",
set: ({ set }, newValue) => {
//newValue : app.tsx의 setHours()로 보낸 값.
const minutes = Number(newValue) * 60;
set(minutesStateAtom, minutes);
},
});