[React] ๐Ÿ“•Recoil ๋กœ์ปฌ, ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€ (ft. ๋งŒ๋ฃŒ์‹œ๊ฐ„ ์ง€์ •)

TATAยท2023๋…„ 10์›” 5์ผ
0

React

๋ชฉ๋ก ๋ณด๊ธฐ
31/32

๐Ÿ“• Recoil ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€

Local Storage

const localStorageEffect = key => ({setSelf, onSet}) => {
  const savedValue = localStorage.getItem(key)
  if (savedValue != null) {
    setSelf(JSON.parse(savedValue));
  }

  onSet((newValue, _, isReset) => {
    isReset
      ? localStorage.removeItem(key)
      : localStorage.setItem(key, JSON.stringify(newValue));
  });
};

typescript ์ถ”๊ฐ€

import { AtomEffect } from 'recoil';

const localStorageEffect: <T>(key: string) => AtomEffect<T> =
  (key: string) =>
  ({ setSelf, onSet }) => {
    const savedValue = localStorage.getItem(key);
    if (savedValue != null) {
      setSelf(JSON.parse(savedValue));
    }

    onSet((newValue, _, isReset) => {
      isReset ? localStorage.removeItem(key) : localStorage.setItem(key, JSON.stringify(newValue));
    });
  };

export default localStorageEffect;

์›ํ•˜๋Š” atom์— ์ ์šฉ

const currentUserIDState = atom({
  key: 'CurrentUserID',
  default: 1,
  effects: [
    localStorageEffect('current_user'), // โญ๏ธ์ถ”๊ฐ€
  ]
});

๐Ÿ“• ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€ ๋งŒ๋ฃŒ ์‹œ๊ฐ„ ์ง€์ •ํ•˜๊ธฐ

import { AtomEffect } from 'recoil';

// ์›ํ•˜๋Š” ์‹œ๊ฐ„ ์ง€์ •
const ONE_HOUR = 3600 * 1000; // 1์‹œ๊ฐ„
const getExpirationTime = () => Date.now() + ONE_HOUR;

const localStorageEffect: <T>(key: string) => AtomEffect<T> =
  (key: string) =>
  ({ setSelf, onSet }) => {
    // ๋กœ์ปฌ์— ์ €์žฅ๋œ ํ‚ค ๊ฐ€์ ธ์˜ค๊ธฐ
    const savedValue = localStorage.getItem(key);
    const expirationTime = localStorage.getItem(`${key}_expiration`);

    // ๋งŒ๋ฃŒ ์‹œ๊ฐ„์ด ์ง€๋‚ฌ๊ฑฐ๋‚˜ ๊ฐ’์ด ์—†์„ ๊ฒฝ์šฐ ์‚ญ์ œ
    if (expirationTime && Date.now() > parseInt(expirationTime, 10)) {
      localStorage.removeItem(key); // ๊ฐ’ ์‚ญ์ œ
      localStorage.removeItem(`${key}_expiration`); // ๋งŒ๋ฃŒ ์‹œ๊ฐ„ ์ •๋ณด ์‚ญ์ œ
    } else if (savedValue != null) {
      // ๋งŒ๋ฃŒ ์‹œ๊ฐ„์ด ์ง€๋‚˜์ง€ ์•Š์•˜๊ณ , ๊ฐ’์ด ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ํ•ด๋‹น ๊ฐ’์„ Recoil ์ƒํƒœ์— ์„ค์ •
      setSelf(JSON.parse(savedValue));
    }

    // Recoil ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ •์˜
    onSet((newValue, _, isReset) => {
      // Recoil ์ƒํƒœ๊ฐ€ ์žฌ์„ค์ •๋˜๋Š” ๊ฒฝ์šฐ, ํ•ด๋‹น ํ‚ค์™€ ๋งŒ๋ฃŒ ์‹œ๊ฐ„ ์ •๋ณด๋ฅผ ์‚ญ์ œ
      if (isReset) {
        localStorage.removeItem(key);
        localStorage.removeItem(`${key}_expiration`);
      } else {
        // Recoil ์ƒํƒœ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๋Š” ๊ฒฝ์šฐ, ์ƒˆ๋กœ์šด ๊ฐ’์„ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜๊ณ  ๋งŒ๋ฃŒ ์‹œ๊ฐ„ ์ •๋ณด๋ฅผ ๊ฐฑ์‹ 
        localStorage.setItem(key, JSON.stringify(newValue)); // ๊ฐ’ ์ €์žฅ
        localStorage.setItem(`${key}_expiration`, getExpirationTime().toString()); // ๋งŒ๋ฃŒ ์‹œ๊ฐ„ ๊ฐฑ์‹ 
      }
    });
  };

export default localStorageEffect;

โ–ท recoil-persist

๐Ÿ“• ์„ธ์…˜์Šคํ† ๋ฆฌ์ง€

recoil-persist๋กœ sessionStorage ๋˜๋Š” localStorage๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

import { atom } from 'recoil';
import { recoilPersist } from 'recoil-persist';

const sessionStorage = 
      typeof window !== 'undefined' ? window.sessionStorage : undefined

const { persistAtom } = recoilPersist({
  key: 'music',
  storage: sessionStorage,
});

const musicAtom = atom<MyAtomType>({
  key: 'musicAtom',
  default: myDefaultState,
  effects_UNSTABLE: [persistAtom], // โญ๏ธ ์ถ”๊ฐ€
});

๐Ÿ“• SSR ๋Œ€์‘

SSR ๋Œ€์‘๋ฒ•

/* hook */
import { useEffect, useState } from 'react';
import { useRecoilState } from 'recoil';
import currentTrackState, { currentTrackDefault } from 'src/atom/currentTrackState';

const useCurrentTrackSSR = () => {
  const [isInitial, setIsInitial] = useState(true);
  const [value, setValue] = useRecoilState(currentTrackState);

  useEffect(() => {
    setIsInitial(false);
  }, []);

  return [isInitial ? currentTrackDefault : value, setValue] as const;
};

export default useCurrentTrackSSR;
/* ์ตœ์ƒ์œ„์—์„œ ํ•œ๋ฒˆ๋งŒ ์‚ฌ์šฉ */
const [currentMusicAndTrack, setCurrentMusicAndTrack] = useCurrentTrackSSR();




๐Ÿ’Recoil ์‚ฌ์šฉ๋ฒ• ๋ณด๋Ÿฌ๊ฐ€๊ธฐ

profile
๐Ÿพ

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