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๋ก 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], // โญ๏ธ ์ถ๊ฐ
});
/* 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();