-요구사항-
"즐겨찾기"된 데이터는 로컬에 저장하여, 다음에 접속 했을 때, 즐겨찾기 조회가 되어야 합니니다..??!?💢💥
개발 요건에 Recoil 사용 우대라는 말에 홀려 거의 모든 상태를 recoil로 떡칠해버린 죄였을까...
즐겨찾기 목록을 로컬에서 가져올때 문제가 생겨버렸다.
recoil state
// 즐겨찾기 리스트
const bookMarkList = atom<IMovie[]>({
key: 'GripBookMark',
default: [],
})
// 즐겨찾기|즐겨찾기 취소할 IMovie 객체
const pickMovie = atom<IMovie>({
key: 'pickMovie',
default: undefined,
})
// pickMovie가 즐겨찾기 리스트에 존재하면 false, 아니면 true
const bookMarkButtonState = selector<boolean>({
key: 'bookMarkButtonState',
get: ({ get }) => {
const booklist = get(bookMarkList)
const pickedMoive = get(pickMovie)
const result = booklist.filter(book => book.imdbID === pickedMoive.imdbID)
if (result.length === 0)
return true
return false
}
})
bookMarkList
를 갱신한다.bookMarkList
는 recoil값이므로 즐겨찾기 탭이 리렌더링 된다.bookMarkList
값이 변할때마다 localStorage에 저장한다.bookMarkList
에 갱신한다.즉 Modal component에서 값을 추가|삭제 하면
bookMarkList
는 갱신되고 useEffect에서 localStorage에 갱신된 값을 저장한다.
- code-2
useEffect(() => { // 해당 컴포넌트가 onMount와 리렌더링 될때마다. const readData = localStorage.getItem('GripBookMark') as string if(!readData){ setBookMarkList([]) } else{ setBookMarkList(JSON.parse(readData)) } // 해당 컴포넌트가 unMount 될 때마다. return () => { const setData = JSON.stringify(markList) localStorage.setItem('GripBookMark', setData) } }, [bookMarkList])
뇌🧠: "값이 변경될 때마다 저장하고 가져올 수 있잖아?!"
React💻: "돼나 봐라ㅋㅋㅋㅋㅋㅋㅋㅋㅋ"
뇌🧠: "아 안됌?ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ"
새로고침(F5)을 누르거나 react를 다시 시작하면 localStorage에는 빈 배열만 저장된다.
문제의 원인은 code-1에 있다. 바로 recoil 값인 bookMarkList
다.
React💻가 다시 시작되면서 default 값인 빈 배열이 로드되면서 localStorage에 저장되기 때문이다.
React💻: "수고해라 닝겐"
뇌🧠: "엉망이네..."
뇌🧠: "그러면 recoil default에 localStorage 값을 넣으면 되는거 아님?"
맞다. default 값을 처음부터 localStorage 값으로 설정하면 된다. 그러면 code-2의 내용이 없어도 새로고침을 해도 default값이 localStorage이므로 잘 작동한다.
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));
});
};
const currentUserIDState = atom({
key: 'CurrentUserID',
default: 1,
effects: [
localStorageEffect('current_user'),
]
});
Typescript가 시급하다.....😂
여차저차 해서 아래처럼 수정을 했다.
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))
})
}
const bookMarkList = atom<IMovie[]>({
key: 'GripBookMark',
default: [],
effects: [
localStorageEffect<IMovie[]>('GripBookMark')
]
})
타입을 바꾸고 다시 실행해 보았다.
결과는!!!!
effects
를 effects_UNSTABLE
로 바꿔주니 문제가 해결되었다. 빌드할 때 문제는 없지만 해당 문제는 공식해결 방식이 나오지 않은 상태이다.
이제 localStorage에 저장하거나 가져오기 위한 귀찮은 짓은 하지 않아도 된다.
즐겨찾기 값이 변경될 때마다 localStorage에 저장하고 그 값을 bookMarkList
가 잘 읽는다.
다른 방법으로는 recoil-persist가 존재한다. 해당 라이브러리는 간단하게 사용할 수 있어 좋은 것 같다.