현재 네컷지도라는 프로젝트를 진행하면서 카카오맵을 사용하고 있다. Api 응답값으로 해당 지점의 위도, 경도를 받아 마커를 뿌려줘야 되는 기능을 구현하면서 스크립트를 불러오는 방식에 대해서 고민한 흔적에 대해 정리하고자 해당 포스팅을 준비했다. 카카오맵을 사용하는 자세한 방법에 대해서는 이번 포스팅에서는 다루지 않기 때문에 이 점은 고려하여 읽어주시면 되겠다.
사전 준비
카카오 맵 API를 사용하기 위해서는 Kakao Developers에 접속해서 애플리케이션을 추가하고 해당 애플리케이션의 javascript 키 값을 알아야한다. 이 과정에 대해서는 카카오 로그인 구현 포스팅에서 다루기 때문에, 사전 준비에 해당하는 과정은 이전 카카오 로그인 구현 포스팅을 참고하기 바란다.
카카오맵 API 불러오기
위의 사진에서 보는것처럼 카카오맵 사용을 위해서는 실제 지도를 그리는 카카오맵 javascript API를 불러와야한다. CSR로 동작하는 React는 index.html 파일내에 해당 script 코드를 추가해줄수 있지만, index.html 파일이 존재하지 않는 nextjs에서는 해당 API를 불러오는 방법은 react와는 다른 방식으로 진행된다. 카카오맵 구현을 위해 시도했던 세 가지 방법을 소개해보도록 하겠다.
1. _document 파일 내에서 script 불러오기
_document 파일은 공통적으로 모든 페이지에서 활용하는 태그안에 들어갈 내용을 작성할 수 있다. 따라서 _document 파일내에서 script를 불러오는 방법을 사용할 수 있고, 위의 카카오맵 가이드에 명시되어있듯이, 반드시 실행 코드보다 먼저 페이지가 상호작용하기 전에 스크립트를 불러와야 하기 때문에 'next/script'의 Script 컴포넌트를 사용하여 옵셔널 props인 strategy를 beforeInteractive로 설정한다.
import { Html, Head, Main, NextScript } from 'next/document';
import Script from 'next/script';
export default function Document() {
return (
<Html lang="en">
<Head>
<Script
src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_MAP_API_KEY}&libraries=services,clusterer&autoload=false`}
strategy="beforeInteractive"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
이렇게 _document 파일 내에 해당 카카오맵 스크립트를 추가하여 페이지가 hydration이 일어나기 전에 스크립트 로드가 완료되고, 정상적으로 카카오 맵 api를 사용할 준비가 완료된다. 하지만 다수의 페이지에서 카카오맵이 필요한 경우라면 문제가 되지않지만, 특정 페이지 내에서만 카카오맵 api를 사용하게 된다면 불필요하게 스크립트가 로드되는 문제점이 있을 것이라고 판단했고, 다른 방법을 찾아보기로 했다.
Nextjs Script Strategy
위에서 언급한 다른 방법에 대해서 설명하기 전에 Nextjs에서 제공하는 스크립트 컴포넌트의 strategy props중 beforInteractive와 afterInteractive에 대해서 간략하게 설명하도록하겠다. Nextjs의 script에 대한 자세한 설명은 공식 문서에서 확인할 수 있다.
beforeInteractive : 페이지가 상호작용되기 전에 로드, 서버에서 초기 html을 보낼 때 주입되고 페이지가 상호작용 되기 전에 스트립트를 필요로 할 때 생성, _document 파일 내에서만 사용할 수 있도록 고안.
afterInteractive : next/script의 Script 컴포넌트 default 값으로, 페이지가 상호작용 가능해진 직후에 로드
2. 커스텀 Script 컴포넌트 생성 (실패)
다음 코드처럼 카카오 맵이 필요한 특정 페이지 내에서만 스크립트를 로드하기 위해서 커스텀 Script 컴포넌트를 만들어 필요한 페이지에 import하여 사용하려고 했지만,
import Script from 'next/script';
const Scripts = () => {
return (
<>
<Script
src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_MAP_API_KEY}&libraries=services,clusterer&autoload=false`}
strategy="beforeInteractive"
/>
</>
);
};
export default Scripts;
위에서 설명한 strategy의 요구사항을 간과하고 _document 파일 외부에서 beforeInteractive를 적용하니 다음과 같은 에러 메시지가 노출됐다. 따라서 커스텀 Script 컴포넌트를 생성하여 사용하는 방식은 실패했다. 하지만, 상호작용 전에 로드되어야 하는 스크립트가 아니라면 위처럼 스크립트를 적용할 수 있는 방법이 있다는 것을 알게되었다.
3. Nextjs onload props 사용
Nextjs가 제공하는 next/script의 Script 컴포넌트에는 onLoad라는 props도 존재한다. 해당 props는 스크립트가 실행될 때 함께 실행되어야 하는 코드가 존재하는 경우 onLoad props에 함수를 전달하여 스크립트 로드가 완료되고 해당 함수가 실행될 수 있도록 한다. 다음 코드를 살펴보자.
import Script from 'next/script';
import { Dispatch, SetStateAction, useEffect } from 'react';
type ScriptsProps = {
onLoad: Dispatch<SetStateAction<boolean>>;
};
const Scripts = ({ onLoad }: ScriptsProps) => {
return (
<>
<Script
src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_MAP_API_KEY}&libraries=services,clusterer&autoload=false`}
onLoad={onLoad}
/>
</>
);
};
export default Scripts;
위에서 설명한 두번째 방법에서 strategy를 설정하는 대신 onLoad props에 setState 함수인 setMapLoaded를 전달한다.
...
import Scripts from '@components/Scripts';
const ShopDetail = ({ shopId, distance }) => {
...
const [mapLoaded, setMapLoaded] = useState<boolean>(false);
const mapContainer = useRef<HTMLDivElement>(null);
const { data: shopInfo } = useGetShopDetail(shopId, distance);
useEffect(() => {
if (shopInfo && mapLoaded) {
const { kakao } = window;
kakao.maps.load(() => {
const options = {
center: new kakao.maps.LatLng(
Number(shopInfo?.latitude),
Number(shopInfo?.longitude),
),
level: 2,
};
const map = new kakao.maps.Map(mapContainer.current, options);
});
}
}, [shopInfo, mapLoaded]);
return (
<ShopLayout>
<Scripts onLoad={() => setMapLoaded(true)} />
<div ref={mapContainer}></div>
...
</ShopLayout>
);
};
위의 방법을 통해 모든 페이지가 아닌 script가 필요한 페이지에서만 로드되고, script 로드 후 커스텀 Script 컴포넌트로 전달되는 setState 함수가 실행됨에 따라 mapLoaded가 true가 되어 카카오톡 실행코드가 실행된다.
이번 포스팅에서는 Nextjs의 script 사용방법에 대해서 알아보았는데, 이 글을 보는 다른 개발자 분들도 상호작용 전 후로 필요한 script 로드 방법에 따라 대처하는 방식을 효과적으로 사용할 수 있길바란다.
'개발' 카테고리의 다른 글
[개발] 페이지 접근 제한 구현 (0) | 2023.04.17 |
---|---|
[React] Debounce 훅 구현하기 (0) | 2023.04.13 |
[개발] 카카오 로그인 구현하기 (0) | 2023.03.27 |
Yarn-berry + NextJS(typescript) 보일러플레이트 만들기 (0) | 2023.03.05 |
[개발] React-query를 활용한 낙관적 업데이트 (0) | 2023.02.28 |