일반적으로 useEffect Hook을 사용하여 맨 처음 로컬스토리지에 값이 저장되어 있는 경우 그 값을 사용하고, 아니면 초기값으로 셋팅해주면 된다. 나는 현재 상태 관리 방식으로 Recoil을 사용하고 있는데, Recoil Effects 공식문서를 보니 effects를 사용하도록 권장하더라.
Compared to React Effects (React Effects와 비교)
Atom Effects는 대부분의 경우 리액트의 useEffect()로 대체될 수 있습니다. 그러나 atom의 집합은 리액트 컨텍스트의 외부에서 생성되며, 특히 동적으로 생성된 atom의 경우 리액트 컴포넌트 내에서 효과를 관리하기 어려울 수 있습니다. 또한 초기 atom 값을 초기화하거나 서버 사이드 렌더링(SSR)과 함께 사용될 수도 없습니다. atom effects를 사용하는 것은 effects와 atom 정의를 함께 배치하게 합니다.
따라서 공식 문서의 설명에 맞춰 localStorage에 값을 저장할 수 있도록 코드를 작성했다.
const localStorageEffect = (key:string) => ({setSelf, onSet}: any) => {
const savedValue = localStorage.getItem(key)
// setSelf : Callbacks to set or reset the value of the atom.
if (savedValue != null) {
setSelf(JSON.parse(savedValue));
}
// onSet : Subscribe to changes in the atom value.
onSet((newValue:any, _:any, isReset:any) => {
isReset
? localStorage.removeItem(key)
: localStorage.setItem(key, JSON.stringify(newValue));
});
};
위와 같이 함수를 작성해준 다음 atom을 정의해주는 부분에 effects를 추가하면 된다.
/* 선택된 날짜 State */
// 서비스 시작 화면은 오늘날짜, 날짜 기준 수정 가능
const today = new Date();
export const selectedDateState = atom<Date>({
key: "selectedDateState",
default: today,
effects: [localStorageEffect('selected_date')]
});
effects: [localStorageEffect('selected_date')] 이 부분이 로컬스토리지에 전달된 문자열을 키 값으로 데이터를 저장하도록 한다.
useEffect()를 사용해서 해당 recoil의 set함수를 호출하기 전까지는 값을 호출해보면 제대로 값이 들어가있으나 local storage에서는 찾아볼 수 없다. 흠...
일단 set함수를 사용하여 예전 상태에 기반한 업데이트를 하면 default 값이 잘 들어가 있으니 일단은 크게 코드를 바꿀 건 없어서 좋았다.
effects를 사용한다고 useRecoilState()를 사용하는 방법이 달라지는 것은 아니다
Local storage에 데이터를 입출력할 때 사용되는 포맷은 JSON이다.
따라서 나는 JS에서 지원하는 Date객체를 사용해서 데이터를 넣었음에도 데이터를 빼보면 dateString으로 실제로는 문자열 데이터가 리턴된다. 따라서 실제로 사용할 때는 new Date()로 감싸서 Date 객체로 만들어줘야 Date 자료형으로 잘 작동한다.
JSON에서 넣고 뺄 때 자료형이 바뀌니 주의하자! (이건 Backend와 통신할 때도 똑같다.)