dev-debris / coin-simulator

https://coin-simulator.vercel.app
1 stars 0 forks source link

Recoil Effect 사용시 Error #42

Closed SunNacho closed 1 year ago

SunNacho commented 1 year ago
스크린샷 2023-03-28 오전 10 20 23

사진과 같이 effect 기능을 사용하여 atom과 storage를 연동했는데요, 이 상태에서 즐겨찾기 토글을 누르면 다음과 같은 오류가 뜹니다

스크린샷 2023-03-28 오전 10 21 34

favorites은 useRecoilValue로 읽은 데이터이고 switchdata는 data와 favorites을 선택하는 변수입니다.

스크린샷 2023-03-28 오전 10 25 13 스크린샷 2023-03-28 오전 10 26 24

또한 즐겨찾기 버튼을 누를 때에는 다음과 같은 오류가 뜹니다

스크린샷 2023-03-28 오전 10 22 08

effect부분을 삭제하고 다시 눌러보면 정상적으로 작동하는걸로 보아, effect를 사용한게 문제인것 같은데, 왜 저런 오류가 뜰까요? favorites의 타입을 인식하지 못하는 걸까요? 어떤 오류인지 감이 오지 않아 물어봅니다 ㅠ

참고로 effect에 있는 LocalStorage는 next.js에서 localstorage접근 시 뜨는 오류를 방지하기 위해 다음과 같이 클래스화 시켜 import한 함수입니다.

스크린샷 2023-03-28 오전 10 24 13

머리가 너무 아파용 ㅜㅜ살려주세요

akh9804 commented 1 year ago

브라우저가 아닌 서버에서 실행될 때 문제가 되는 것 같아서 찾아보니 recoil-persist는 이런 방법으로 해결해주고 있는 것 같아요.

const localStorageEffect = () => {
  if (typeof window === 'undefined') {
    // 서버에서 실행되는 Effet 함수
    return () => {};
  }

  // 브라우저에서 실행되는 Effect 함수는 여기에다 작성
  // 여기에선 localStorage 접근 가능
}

atom({
  effects: [localStorageEffect()]
})
SunNacho commented 1 year ago
스크린샷 2023-03-30 오전 9 42 13

effect함수에 사용되는 setSelf와 onSet을 어떻게 처리해야 할까요?? if(typeof window ==='undefined') {return ()=>{}} 를 atom effect함수 안에 넣어보기도 해봤지만 잘 안되네욤 ㅠㅠ

akh9804 commented 1 year ago

흠 한 번 요렇게 해볼래요? 반환 타입을 지정해주면 될 것 같아요

그리고 다른 곳에서도 범용적으로 쓰여야 하니까 스토리지에서 사용할 key 값, 사용할 스토어를 인자로 받으면 좋을 것 같아요ㅎㅎ

import { AtomEffect } from 'recoil'

function storageEffect<T = any>(key: string, storage: localStorage | sessionStorage = localStorage): AtomEffect<T> {
  if (typeof window === 'undefined') {
    return () => {};
  }

  return ({setSelf, onSet}) => {...}
}

atom({
  effects: [localStorageEffect('favoriteList')]
})
SunNacho commented 1 year ago
스크린샷 2023-03-30 오전 10 32 35

제가 이해를 잘 한게 맞을까요? effects:[storageEffect('favoriteList',localstorage)라고 적는게 맞을까요...

스크린샷 2023-03-30 오전 10 33 47

아직은 같은 오류가 생깁니다

SunNacho commented 1 year ago
스크린샷 2023-03-30 오전 10 35 37

위의 빨간줄의 문제 해결 도움 양식에선 typeof localstorage를 쓰는 것을 추천하길래 그렇게 변경했더니

스크린샷 2023-03-30 오전 10 36 15

이렇게 나타납니담 ㅠ

akh9804 commented 1 year ago

아 맞네요 typeof로 써야했네

그럼 옵션을 문자열로 받아서 사용하는 게 좋겠네요. 접근만 해도 오류가 나는구나.

import { AtomEffect } from 'recoil'

function storageEffect<T = any>(key: string, type: 'localStorage' | 'sessionStorage' = 'localStorage'): AtomEffect<T> {
  if (typeof window === 'undefined') {
    return () => {};
  }

  const storage = type === 'localStorage' ? localStorage : sessionStorage;

  return ({setSelf, onSet}) => {...}
}

atom({
  effects: [localStorageEffect('favoriteList')]
})
SunNacho commented 1 year ago
스크린샷 2023-03-30 오후 5 09 07

이제 경고줄은 없어졌습니다!! 그런데...

스크린샷 2023-03-30 오후 5 09 28

즐겨찾기 버튼을 누르면 여전히 favorites을 인식못하는 상황이네요 ㅠㅠ 코드는 pr에 올려놓은거에서 건들지 않았습니다

akh9804 commented 1 year ago

아무래도 현재 localStorage에 저장되어 있는 값의 형태가 배열이 아닌가보네요. 개발자 도구에 들어가서 다 지워볼래요?

아래처럼 정의하고 사용하니까 저는 잘 되더라구요.

function storageEffect<T>(key: string, type: 'localStorage' | 'sessionStorage' = 'localStorage'): AtomEffect<T> {
  if (typeof window === 'undefined') {
    return () => {};
  }

  const storage = type === 'localStorage' ? localStorage : sessionStorage;

  return ({setSelf, onSet}) => {
    const savedData = storage.getItem(key);

    if (savedData) {
      setSelf(JSON.parse(savedData));
    }

    onSet((newValue, _, isReset) => {
      isReset ? storage.removeItem(key) : storage.setItem(key, JSON.stringify(newValue));
    });
  };
}
SunNacho commented 1 year ago

아..이미 저장된 타입과 충돌이 나서 그런걸까요? 이건 정말 혼자선 알아내기 너무 어려운 부분이었네요 ㅠㅠ 내일 근무지 도착하자마자 바로 검토해보겠습니다

SunNacho commented 1 year ago

하 확인했습니다 ㅠㅠ 드디어!!!!행복해