Uncaught runtime errors Script error

g-enesis·2024년 9월 20일
0
post-thumbnail

프로젝트를 진행하면서 카카오지도API를 사용했다.
map을 불러오기위해 script를 useEffect안에 비동기로 가져오는 부분을 작성했다.
그러다가 Uncaught runtime errors를 마주했다.

Code

useEffect(() => {
    const script = document.createElement('script');
    script.src = `https://dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.REACT_APP_KAKAO_APP_KEY}&autoload=false`;
    script.async = true;

    document.head.appendChild(script);

    script.onload = () => {
      window.kakao.maps.load(() => {
        const position = new window.kakao.maps.LatLng(
          location.lat,
          location.lng,
        );
        const options = {
          center: position,
          level: 3,
        };
        const marker = new window.kakao.maps.Marker({
          position,
        });
        const map = window.kakao.maps.Map(mapContainer.current, options);
        marker.setMap(map);
      });
    };
  }, [location.lat, location.lng]);

Error

Uncaught runtime errors:
×
ERROR
Script error.
    at handleError (http://localhost:3000/static/js/bundle.js:43828:58)
    at http://localhost:3000/static/js/bundle.js:43847:7
ERROR
Script error.
    at handleError (http://localhost:3000/static/js/bundle.js:43828:58)
    at http://localhost:3000/static/js/bundle.js:43847:7

위 코드에서 무엇이 잘못됐을까?
우선 async=true만 사용해서 스크립트가 로드되자마자 실행이 된 것으로 보인다.
이 말은 DOM이 완전히 로드되지 않았을 때 실행될 가능성이 있었고 이에 따른 예외를 하나씩 처리해본다.

따라서 아래 해결방법을 적용했다.

1. script.defer = true 추가

  • defer 속성은 이런 타이밍 문제를 해결할 수 있다.
    일단 스크립트가 비동기적으로 로드되지만, HTML 파싱이 완료된 후에 스크립트가 실행되도록 보장한다.

2. window.kakao && window.kakao.maps 객체 체크 추가

  • window.kakao와 window.kakao.maps가 존재하는지 체크한 후에 maps.load를 호출한다.
    기존코드에서는 이 체크가 없었기 때문에, window.kakao가 아직 로드되지 않은 상황에서 window.kakao.maps.load를 호출하려다 에러가 발생했을 수 있다.

3. clean-up 함수 추가

  • 컴포넌트가 언마운트될 때 스크립트를 제거하는 클린업 함수를 추가했다. 이로 인해, 페이지가 변경되거나 컴포넌트가 사라질 때 불필요한 스크립트가 남아 있는 상황을 방지할 수 있었다.
    기존코드에서는 이 클린업 과정이 없었기 때문에, 스크립트가 여러 번 불필요하게 로드되거나 다른 리소스와 충돌했을 수 있다.

4. location 의존성 단순화

  • 두 번째 코드에서는 useEffect의 의존성 배열에서 location.lat, location.lng 대신 location 객체 전체를 넣었다.
    location.lat, location.lng를 각각 의존성으로 넣은 경우, 변경 사항을 정확히 추적하지 못하거나 잘못된 상태에서 의존성 변화를 감지하여 불필요하게 리렌더링될 가능성이 있었다.

💡 최종적으로 수정된 코드

useEffect(() => {
  const script = document.createElement('script');
  script.src = `https://dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.REACT_APP_KAKAO_APP_KEY}&autoload=false`;
  script.async = true;
  script.defer = true;

  document.head.appendChild(script);

  script.onload = () => {
    if (window.kakao && window.kakao.maps) {
      window.kakao.maps.load(() => {
        const position = new window.kakao.maps.LatLng(
          location.lat,
          location.lng,
        );
        const options = {
          center: position,
          level: 3,
        };
        const map = new window.kakao.maps.Map(mapContainer.current, options);
        const marker = new window.kakao.maps.Marker({
          position,
        });
        marker.setMap(map);
      });
    }
  };

  // clean-up
  return () => {
    document.head.removeChild(script);
  };
}, [location]);
profile
Frontend Developer

0개의 댓글