[React] TS + Recoil global state 사용하기. (다크모드 구현)

mangosteen·2024년 3월 18일

react

목록 보기
3/8

동일한 state를 다른 components에서 사용해야 할 때, props 대신에 상태관리 라이브러리 recoil로 grobal state 버블(atom)을 생성해서 사용할 수 있다.

Recoil 시작하기 문서
https://recoiljs.org/ko/docs/introduction/getting-started/

  1. npm install recoil명령어로 recoil을 install한다.
  2. RecoilRoot를 부모 트리에 넣어준다. app, index..등..
// index.tsx

import { RecoilRoot } from "recoil";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <RecoilRoot>
      <App />
  </RecoilRoot>
);
  1. atom.ts를 생성한다. Atom은 상태(state)의 일부를 나타낸다.
    구독하는 components들에서 읽고, 쓸 수 있고, 상태가 변화될 때 재랜더링된다.
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,
});
  1. 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);
  1. 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>
    </>
  );
}
  1. 기타 ThemeProvider 사용하여 darkMode/lightMode 구현은 아래 styled-components 참고

[React] TS + Theme(styled-components)
https://velog.io/@mangosteen977/React-TS-Temestyled-components

  1. selector
    recoil의 selector는 atom state로 부터 파생 된 상태(derived state)의 일부이다.

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);
  },
});
profile
Mong muốn trở thành chủ cuộc sống của tôi🔥.

0개의 댓글