[React] recoil state management

JIOOยท2023๋…„ 12์›” 18์ผ
0

React

๋ชฉ๋ก ๋ณด๊ธฐ
13/19
post-thumbnail

๐Ÿ“– ์ƒˆ๋กœ์šด ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์ž

recoil์€ react์˜ ์ƒํƒœ๊ด€๋ฆฌ management์ค‘ ํ•˜๋‚˜๋กœ ์ƒํƒœ๊ด€๋ฆฌ๋ฅผ ์ „์—ญ์œผ๋กœ ๊ด€๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.

์ด ๊ธ€์„ ์ฝ๋Š” ๋…์ž๋Š” redux๋ฅผ ํ•œ๋ฒˆ ์ •๋„ ๋ผ๋„ ์ ‘ํ•ด๋ณธ ์‚ฌ๋žŒ์ด ์ฝ์œผ๋ฉด ๋„์›€์ด ๋  ๊ฒƒ์ด๋‹ค.


recoil์„ ์„ค์น˜ํ•œ ํ›„ redux์˜ provider ์ฒ˜๋Ÿผ RecoilRoot๋ž€ ๊ฑธ import ํ•œ ํ›„
root์— ๋ Œ๋”๋ง ์ค‘์ธ App ์ปดํฌ๋„ŒํŠธ๋ฅผ RecoilRoot๋กœ ๊ฐ์‹ธ์ค€๋‹ค.

recoil ์—๋Š” recoil ๋งŒ์˜ state๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ ๊ทธ๊ฑธ atom ์ด๋ผ๊ณ  ํ•œ๋‹ค

ATom

export const atomState = atom({
 key : "์ž‘๋ช…",
 value : ๊ฐ’
})

์‚ฌ์šฉ ํ•  ์ปดํฌ๋„ŒํŠธ์—์„œ useState ์ฒ˜๋Ÿผ import atomState from ~ ์ฃผ์†Œ

const [state,setRState] = useRecoilState(atomState) ์ด๋ ‡๊ฒŒ ์“ฐ๋ฉด ๋œ๋‹ค.


์ƒํƒœ ๋ณ€๊ฒฝํ•˜๋Š”๋ฒ•: ๊ทธ๋ƒฅ ์ €๋ ‡๊ฒŒ ๋ถˆ๋Ÿฌ์˜ค๊ฒŒ ๋˜๋ฉด ์–ด๋””์„œ๋“  setRState() ์ด๋ ‡๊ฒŒ ํ•ด์ฃผ๋ฉด ๋ฐ”๋€œ

  1. useState ์ฒ˜๋Ÿผ button onclick={() => setRState(์•ก์…˜)} ์ด๋ ‡๊ฒŒ ํ•ด์ฃผ๋ฉด ๋จ

  2. setRstate๊ฐ€ ์ž‘๋™ํ•ด์„œ atomState์˜ value ๊ฐ’์ด ๋ฐ”๋€œ // ์ด๊ฑธ ๊ตฌ๋…์ด๋ผ๊ณ  ํ•œ๋‹ค.

  3. ์ด๋•Œ setRState๊ฐ€ ์‹คํ–‰๋˜๋ฉด์„œ useRecoilState๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๊ณณ์€ ์ „๋ถ€ ๋ฆฌ๋žœ๋”๋”ฉ ๋œ๋‹ค.


๋‹จ useRecoilValue๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ํ•ด๋‹น ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ํ•œ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฆฌ๋ Œ๋”๋ง๋˜์ง€ ์•Š๋Š”๋‹ค.


recoil hooks

useRecoilState

Recoil์—์„œ๋Š” useRecoilState๋ผ๋Š” hook์„ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์ž๋กœ ์ „๋‹ฌํ•œ ์ƒํƒœ์˜ ๊ฐ’๊ณผ setter๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

const SomeComponent = () => {
  const [mode, setMode] = useRecoilState(modeState);

  return <div>mode: {mode}</div>;
};

useRecoilValue

๋งŒ์•ฝ ์ƒํƒœ ๊ฐ’๋งŒ ํ•„์š”ํ•œ ๊ฒฝ์šฐ, useRecoilValue๋ผ๋Š” hook์„ ์‚ฌ์šฉํ•œ๋‹ค.

const SomeComponent = () => {
  const mode = useRecoilValue(modeState);

  return <div>mode: {mode}</div>;
};

useSetRecoilState

const Button = () => {
  const setMode = useSetRecoilState(modeState);

  const toggleMode = () => {
    setMode(prevMode => (prevMode === 'light' ? 'dark' : 'light'));
  };

  return (
    <button type="button" onClick={toggleMode}>
      ์ €๋ฅผ ํด๋ฆญํ•˜์‹œ๋ฉด mode๊ฐ€ ๋ฐ”๋€Œ์–ด์š”!
    </button>
  );
};

์ด hook์„ ์‚ฌ์šฉํ•˜๋ฉด setter๋งŒ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค.

recoil์˜ ๋น„๋™๊ธฐ

recoil์€ ์•„ํ†ฐ๋งŒ์œผ๋กœ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ํ•  ์ˆ˜ ์—†๋‹ค.
๊ทธ๋ž˜์„œ selector์ด๋ž€ ํ•จ์ˆ˜๋ฅผ ์จ์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.

const cookieData = useRecoilValue(getCookieSelector);
// ์–˜๋Š” ๊ทธ๋ƒฅ getCookieSelector์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์—ญํ• 

export const getCookieSelector = selector({ 
  key: "cookie/get",
  // ๊ณ ์œ ์˜ ํ‚ค๊ฐ’ 
  get:  async ({get}) => {
    try {
      const response = await fetch('/api/cookies'); // ๊ฐ€์ƒ์˜ API ์ฃผ์†Œ
      const data = await response.json();
      return data;
    } catch (error) {
      console.error('Error fetching cookie data:', error);
      throw error;
    }
  },
  
  ์—ฌ๊ธฐ์„œ return data๋ฅผ set ๋ถ€๋ถ„์— 
  set(์•„ํ†ฐ๋ช…, newValue) ์ด๋ ‡๊ฒŒ ๋„ฃ์œผ๋ฉด ์ƒํƒœ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋œ๋‹ค.
  
  set: ({set}, newValue)=> {  //useRecoilState๋ฅผ ์“ฐ๋ฉด ์ž๋™ ์‹คํ–‰
 //return๋œ data.data๊ฐ€ set์œผ๋กœ ๋ณด๋‚ด์ง โ†“
    set(cookieState, newValue)
    //cookieState๋ผ๋Š” ์•„ํ†ฐ์— newValue๋กœ ์ƒํƒœ๊ฐ’์„ ๋ฐ”๊ฟˆ
  }
});
})

get์ด ๋จผ์ € ์‹คํ–‰๋˜๋ƒ set์ด ๋จผ์ € ์‹คํ–‰๋˜๋ƒ๋Š”
useRecoilValue์„ ์ป๋ƒ useRecoilState๋ฅผ ์ป๋ƒ์— ๋‹ฌ๋ ธ๋‹ค

useRecoilState๋Š” get&set ๋‘˜๋‹ค ํ˜ธ์ถœํ•˜๋Š”๋ฐ RecoilValue๋Š” get๋งŒ ํ˜ธ์ถœํ•œ๋‹ค.

๋™์‹œ์— ์ˆ˜ํ–‰๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์‚ฌ์šฉํ•˜๋Š” ์ƒํ™ฉ์— ๋”ฐ๋ผ ํ˜ธ์ถœ๋˜๋Š” ํƒ€์ด๋ฐ์ด ๋‹ค๋ฅด๋‹ค.

์ฒ˜์Œ ๋ Œ๋”๋ง ์‹œ (get):

useRecoilState๋ฅผ ์‚ฌ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฒ˜์Œ ๋ Œ๋”๋ง๋  ๋•Œ get ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๊ณ , ์ด๋•Œ Recoil ์ƒํƒœ์˜ ํ˜„์žฌ ๊ฐ’์„ ์ฝ์–ด ์˜จ๋‹ค.

์ƒํƒœ ์—…๋ฐ์ดํŠธ ์‹œ (set):

useRecoilState๋ฅผ ์‚ฌ์šฉํ•œ ์ปดํฌ๋„ŒํŠธ์—์„œ Recoil ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ๋•Œ, set ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ ,

์ด๋•Œ Recoil์˜ ์ƒํƒœ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋˜๋ฉฐ, ํ•ด๋‹น Recoil์˜ ์ƒํƒœ๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง๋œ๋‹ค.

๋‹ค์‹œ ๋ Œ๋”๋ง๋œ ์ปดํฌ๋„ŒํŠธ์—์„œ useRecoilState๊ฐ€ ์‚ฌ์šฉ๋˜๋ฉด

๋‹ค์‹œ get ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์–ด ์ตœ์‹  ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค.

์ด๋Ÿฌํ•œ ํ๋ฆ„์—์„œ get๊ณผ set์€ ์„œ๋กœ ๋‹ค๋ฅธ ์ƒํ™ฉ์—์„œ ํ˜ธ์ถœ๋˜๋ฉฐ

์ดˆ๊ธฐ ๋ Œ๋”๋ง ์‹œ get์ด ๋จผ์ € ์‹คํ–‰๋˜๊ณ , ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ๋•Œ set์ด ๋จผ์ € ์‹คํ–‰๋œ๋‹ค.


๊ทธ๋ฆฌ๊ณ  ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์ค‘ ๋กœ๋”ฉ๋˜๋Š” ๊ตฌ๊ฐ„์—” suspense์™€ fallback ์ฝ”๋“œ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฒ˜๋ฆฌํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

   <RootRecoil>
      <Suspense fallback={<div>Loading...</div>}> 
      //์ด๋ ‡๊ฒŒ suspense fallback={๋กœ๋”ฉ์ฒ˜๋ฆฌํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋‚˜ div์„ ์จ์ฃผ๋ฉด๋จ} 
      // ๊ทธ๋Ÿผ ๋‹ค๋Œ๋ฉด ๋ฐ‘์— Cookies๊ฐ€ ๋žœ๋”๋ง๋จ
        <Cookies />
      </Suspense>
    </RootRecoil>

Selector์˜ ๋˜๋‹ค๋ฅธ ์˜ˆ์‹œ

selector๋Š” ์‰ฝ๊ฒŒ ๋งํ•ด์„œ ๊ธฐ์กด์— ์„ ์–ธํ•œ atom์„ ์ „/ํ›„ ์ฒ˜๋ฆฌํ•˜์—ฌ ์ƒˆ๋กœ์šด ๊ฐ’์„ ๋ฆฌํ„ดํ•˜๊ฑฐ๋‚˜
๊ธฐ์กด atom์˜ ๊ฐ’์„ ์ˆ˜์ •ํ•˜๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ฐธ์กฐํ•œ atom์˜ ๊ฐ’์ด ์ตœ์‹ ํ™”๋˜๋ฉด ์ž๋™์œผ๋กœ
selector์˜ ๊ฐ’๋„ ์ตœ์‹ ํ™”ํ•˜๋ฏ€๋กœ, ๊ด€๋ฆฌํ•˜๊ธฐ์—๋„ ๊ฐ„ํŽธํ•˜๋‹ค.

export const sampleState = atom({
  key: "sampleState",
  default: 0,
});

export const sampleSelector = selector({
  key: "sampleSelector",
  get: ({ get }) => get(sampleState) * 2,
  set: ({ set }, newValue) => set(sampleState, newValue / 2),
});

๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ์˜ˆ์ œ๋ฅผ ํ•œ๋ฒˆ ๋งŒ๋“ค์–ด๋ดค๋‹ค. sampleSelector๋Š” sampleState๋ฅผ ์ฐธ์กฐํ•ด
sampleState * 2 ๋ผ๋Š” ๊ฐ’์„ ๋ฆฌํ„ดํ•˜๊ณ  ์žˆ๋‹ค.

๋˜ํ•œ setter๋ฅผ ๋ณด๋ฉด ์ƒˆ๋กญ๊ฒŒ ์ž…๋ ฅ๋œ ๊ฐ’์„ ๋‚˜๋ˆ„๊ธฐ 2 ํ•˜์—ฌ sampleState์— ์ ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

์ด์ฒ˜๋Ÿผ selector๋ฅผ ์ด์šฉํ•˜๋ฉด ๊ธฐ์กด์— ์„ ์–ธํ•œ atom๋“ค์„ ์ฐธ์กฐํ•˜์—ฌ ์ƒˆ๋กœ์šด ๊ฐ’์„ ๋งŒ๋“ค์–ด๋‚ด๊ณ ,

์ƒˆ๋กญ๊ฒŒ ์ž…๋ ฅ๋ฐ›์€ ๊ฐ’์„ ํ›„์ฒ˜๋ฆฌํ•˜์—ฌ atom์˜ ๊ฐ’๊นŒ์ง€๋„ ์ˆ˜์ •ํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

profile
ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ ์ข‹์€ ์›น์Ÿ์ด

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด

Powered by GraphCDN, the GraphQL CDN