웹을 개발하면서 최근 검색어나 "오늘 하루 안보기" 팝업 플래그등
브라우저 로컬스토리지를 사용을 자주 하는데요 저는 갤럭시를 사용하기 때문에 인지하지 못했지만
아이폰IOS 아이웨딩앱에서 로컬스토리지가 계속 초기화가 되는 문제가 있었습니다.
IOS wkwebview를 사용하면 모든 저장매체를 초기화하여 호출하는 걸로 알고 있고
현재 아이웨딩 개발자중 IOS개발자는 없고 전 ios개발자였던 퇴사자에게 외주를 맡겨 이슈가 큰 문제들만 외주를
맡기는 상황입니다
IOS를 제외한 user-agent는 웹,안드로이드,크롬,사파리 전부 가능한 문제
일단 IOS일 경우 localstorage setItem할때 레디스 서버에 key/value값을 저장해야 했다
import { isIOS } from 'react-device-detect';
export const setStore = (key: string, value: any) => {
if (isIOS) {
cacheSetLocalstorage(key, value);
}
return localStorage.setItem(key, JSON.stringify(value));
};
key값은 디바이스 UUID로 고유번호로 구분
기존에 value가 있으면 가져오고 새로운 값 저장
const get = await this.cacheService.get(`${device_uuid}_localstorage`);
await this.cacheService.set(
`${device_uuid}_localstorage`,
{ ...get, [key]: value }
);
처음에는 로컬스토리지 get을 사용할 시 api-redis통신을 한번씩 하려고 했지만
누가봐도 좋은 방법은 아니였기 때문에 사용자가 처음 클라이언트 접속시 일괄적으로
redis key/value을 전부 가져와 window.localstorage 일괄 저장하는 방법으로 해결 했다.
_app.tsx에서 ios 웹뷰에서 보내준 디바이스UUID를 서버사이드에서 가져오자
function App({ Component, pageProps, deviceId }: Props) {
const { localstorageBindLoading } = useIOSFirstSetLocalStorage(deviceId);
return {
{!localstorageLoading && (
<Layout >
<Component {...pageProps} />
</Layout>
)}
}
}
export const useIOSFirstSetLocalStorage = deviceId => {
const [localstorageLoading, startLocalStorage] = useState(false);
const isMount = global.window && window.localStorage.getItem('isSuccess');
const setIosLocalStorage = async () => {
const result = await cacheLocalstorage(deviceId);
if (empty(result)) {
Object.entries({ ...result, isSuccess: true }).forEach(([key, value]) => {
localStorage.setItem(key, JSON.stringify(value));
});
}
return startLocalStorage(false);
};
useEffect(() => {
if (isIOS && !empty(isMount)) {
startLocalStorage(true);
localStorage.setItem('deviceId', deviceId);
setIosLocalStorage();
}
}, [isIOS, isMount]);
return { localstorageLoading };
};
레디스에서 모든 key/value 리스트를 받아오면 객체형식으로 받아오기 때문에
Object.entries로 배열 정규화를 시킨후 반복문을 이용해서 순차적으로 localstorage로 저장하는 구조이다
매번 page로드시 _app.tsx에서 해당 훅을 실행시키면 안되기 때문에 isSuccess플래그를 추가로 넣어 처음 웹뷰 접속시에만 해당 로직이 돌아가도록 하였다
_app.tsx에 존재하는 Layout컴포넌트에서 팝업이 이루어질경우 useIOSFirstSetLocalStorage처리하는과정에서 localstorage를 사용하지 못한다.
그래서 처리하는동안 localstorageLoading을 이용하여 처리가 완료되면 Layout으로 넘어가도록 하였다
로컬스토리지를 저장할때마다 api통신을 하는것이 계속 걸려서 클라이언트에서 레디스 접속하여 pub/sub 하는 라이브러리를 찾던 중
ioredis를 알게 되었고 추후에 ioredis를 활용해서 node와 api통신 없이 처리하는 방법으로 수정을 해야 할 거 같습니다
감사합니다