State Management 없이 Toggle을 구현해보면,
ThemeProvider
를 App()
로 옮겨주고, useState
를 사용하여 구현할 수 있다.
👉 다시 말해, Props 가 traveling 하는 상태라고 할 수 있다.
function App() {
const [isDark, setIsDark] = useState(false);
const toggleDark = () => setIsDark((current)=> !current);
return (
<>
<ThemeProvider theme={isDark ? darkTheme: lightTheme}>
<button onClick={toggleDark}>Toggle Mode</button>
</ThemeProvider>
</>
);
}
위처럼 toggleDark
를 Component 간 계속 전달해줘야 한다!!!
App (isDark, modifierFn)
=> Router => Coins (modifier)
=> Router => Coin => Chart (isDark)
이것이 바로 Global State이다.
✨ Global State: Application 전체에서 공유되는 state
- Global State는 어플리케이션이 무언가를 인지해야 할 때 사용한다.
- 예를 들어 특정 value (여기서는
isDark
)에 접근해야 할 때, 특정 value를 수정해야 할 때(여기서는toggleDark
) 사용한다.
Application 전체에서 무언가를 공유해야 하는 경우?
// state management 없이
isDark: App -> Router -> Coin -> Chart
// state management 사용
Header -> (isDark) <- Chart
이 때 Recoil는 state를 어떤 Atom에 넣어두고, 이 Atom에 접근할 수 있도록 하는 것이 핵심이다.
global state를 application의 분리된 공간, Atom에서 관리할 수 있도록 해준다.
이처럼 state가 ❗특정 Component에 종속되지 않도록 해준다.
따라서 component는 부모의 부모의 부모의 ... 로부터 value를 받아올 필요가 없다.
Recoil 은 ReactJS에서 사용할 수 있는 state management 라이브러리이다. 링크
npm install recoil
atom
파일을 만든다.import { atom } from "recoil";
export const isDarkAtom = atom({
key: "isDark",
default: false
})
useRecoilValue
함수를 사용하면 된다.function Chart({coinId}: ChartProps) {
const isDark = useRecoilValue(isDarkAtom);
...
}
useSetRecoilState
함수를 사용한다.const setDarkAtom = useSetRecoilState(isDarkAtom);
const toggleDarkAtom = () => setDarkAtom((prev)=>!prev);
...
<button onClick={toggleDarkAtom}>Toggle Mode</button>
...
useRecoilValue
와 useSetRecoilState
를 한 번에 사용하려면 useRecoileState
사용하기const [value, modFn] = useRecoilState(toDoState);
// const value = useRecoilValue(toDoState);
// const modFn = useSetRecoilState(toDoState);
Selectors
A 👉selector👈 represents a piece of 📌derived state📌. You can think of derived state as the output of passing state to a pure function that derives a 📌new value from the said state📌. 공식문서
atom의 output을 변형하려면?
👉selector👈 가 state
를 가지고 새로운 뭔가(📌derived state📌)를 return한다.
export const toDoSelector = selector({
key: "toDoSelector",
get: ({get})=>{
const toDos = get(toDoState)
return toDos.length;
},
});
useRecoilValue
를 이용해서 atom의 output, selector의 output을 얻을 수 있다.
Set
Selectors두 개의 atom을 만드는 대신 하나의 state를 가지고 2개의 property를 가지는 selector을 사용할 수 있다.
selector가 활용될 수 있는 경우는,
get
export const toDoSelector = selector({
key: "toDoSelector",
get: ({get})=>{
const toDos = get(toDoState);
const category = get(categoryState);
return toDos.filter((toDo)=> toDo.category === category);
},
});
set
export const hourSelector = selector<number>({
key: "hours",
get: ({get}) => {
const minutes = get(minuteState);
return minutes/60;
},
set: ({set}, newValue) => {
const minutes = Number(newValue) * 60;
set(minuteState, minutes);
}
});
useRecoilState()
const [first, second] = useRecoilState(hourSelector);