웹 개발/프론트엔드

[React] Recoil Cannot Freeze 에러 해결방법

초보군붕이 2022. 11. 13. 20:41
반응형

토이프로젝트를 진행하던 도중 뜬금없이 Cannot Freeze 에러가 발생했다.

 

에러메세지

 

분명 Object.freeze() 메소드를 쓴적이 없는데...해서 좀 더 자세히 살펴보기로 했다.

 

 

● Object.Freeze() 란?

객체의 불변성을 유지하기위해 변경을 차단하는것을 뜻한다.

내부 값을 삭제하거나 변경할 수 없어진다.

 

MDN Docs : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze

 

Object.freeze() - JavaScript | MDN

Object.freeze() 메서드는 객체를 동결합니다. 동결된 객체는 더 이상 변경될 수 없습니다. 즉, 동결된 객체는 새로운 속성을 추가하거나 존재하는 속성을 제거하는 것을 방지하며 존재하는 속성의

developer.mozilla.org

 

하지만 나는 사용한적이 없다. 코드의 디버깅을 계속하다가 업로드된 이미지들을 관리하기 위해 사용한 전역 상태관리 라이브러리인 Recoil에서 에러가 발생한것으로 추정됬따.

 

 

 

● Recoil 이란?

Facebook에서 개발한 React 전역 상태관리 라이브러리 이다.

아직 0.7.6 버전으로 정식 릴리즈 버전은 아니지만 새로운 상태관리 프레임워크를 사용해보고싶어서 도입했다.

또한 사용법도 Redux에 비해 매우 간단해보였다.

 

Recoil Docs : https://recoiljs.org/ko/

 

Recoil

A state management library for React.

recoiljs.org

 

Recoil Github : https://github.com/facebookexperimental/Recoil

 

GitHub - facebookexperimental/Recoil: Recoil is an experimental state management library for React apps. It provides several cap

Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features o...

github.com

 

 

 

● Recoil 라이브러리에서 Cannot Freeze 에러??

공식 홈페이지에서는 freeze로 찾아보니 아무련 결과도 나오지 않았다.. 결국 공식 깃허브 Issue에서 찾아봤다.

 

역시 나만 겪었던 에러가 아닌것 같다. 올해 8월달에 어떤 개발자가 이슈로 등록한게 있었다.

 

GIthub Issue 링크 : https://github.com/facebookexperimental/Recoil/issues/1940

 

Question about the Object.freeze · Issue #1940 · facebookexperimental/Recoil

Does Recoil only do Object.freeze on development build? I have an app using Recoil, when I was using console.log(Object.isFrozen(snapshot.getLoadable(xxxAtom).getValue()) inside a RecoilCallback, I...

github.com

 

Object.freeze Issue

 

해당 에러는 Recoil에서 불변성을 지키기 위해 직접 반환된 값을 변경하고자 할때 에러 방지를 위한 안전장치? 라고 한다.

아마 Object.freeze 메소드로 인한 성능저하를 방지하기위해서 개발자가 걸어둔것으로 추정된다.

만약 해당 오류가 발생할 경우에는 dangerouslyAllowMutability 옵션을 켜면 된다고 한다.

 

하지만 라이브러리 개발자가 의도적으로 성능저하를 방지하기 위해 걸어둔걸 강제로 꺼버리는게 조금 꺼림칙했지만 당장은 방법을 찾을수가 없어서 우선 옵션을 켜고 다시 테스트해봤다.

 

□ UploadImage.tsx

  const imageUploadHandler = (event: ChangeEvent<HTMLInputElement>) => {
    const { files } = event.currentTarget;

    if (files) {
      if (files.length > 4) {
        alert("이미지는 4장까지 업로드가 가능합니다.");
        return;
      }

      /** 문제가 됬던 부분 */
      setUploadImages((uploadImages) => [...uploadImages, files]);

      for (let i = 0; i < files.length; i++) {
        if (!files[i].type.match("image/*")) {
          alert("이미지 파일만 업로드가 가능합니다.");
          setUploadImages([]);
          return;
        }

        const reader = new FileReader();
        reader.onload = (e: any) => {
          setBlobImages((blobImages) => [...blobImages, e.target.result]);
        };
        reader.readAsDataURL(files[i]);
      }
    }
  };

 

□ recoil.ts

/** 업로드된 이미지들 */
export const uploadImageState = atom<FileList[] | never[]>({
  key: "uploadImageState",
  default: [],
  dangerouslyAllowMutability: true,
});

key와 default의 경우 필수적으로 들어가야되는 옵션이며, Cannot Freeze 에러를 해결하기위해 새로운 값을 추가했다.

 

 

 

● 결과는???

이미지 업로드 결과

 

임시방편으로 해결해서 찝찝하지만 해결이 됬다. 

반응형