최근 진행한 팀 프로젝트에서 프론트엔드 개발을 담당했다. 우리 팀은 요즘 현업에서 많이 사용되는 React의 프레임워크인 'NextJS'를 사용해보기로 했다. 내가 구현한 기능 중 Kakao API를 이용한 소셜 공유 기능과 Kakao Map을 띄우는 기능을 NextJS 13 버전에서 어떻게 구현할 수 있는지 알아보도록 하자.
본 포스팅은 카카오 개발자 페이지에서 API KEY를 발급받은 이후의 내용을 담고있다. 아직 API KEY를 발급받지 않았다면, 이곳에서 자바스크립트 API KEY를 발급 받아야 한다.
필자는 이번 프로젝트에서 프론트엔드 경험이 처음이었고, 그렇기에 물론 NextJS는 처음 사용해보았다. 사실 아직 리액트도 공부가 많이 필요하다. Kakao API를 활용한 기능을 구현하기 위해 구글링을 열심히 해보고, 요즘 누구나 사용하는 Chat GPT에게도 도움을 청해보았지만, NextJS 13 버전은 출시된지 얼마 안된 버전이라 그런지 내가 원하는 정보를 얻는게 쉽지 않았다. (물론 내가 못찾은걸수도 있다.) 나와 같은 사람이 한 명 쯤은 있을 것이라 생각하고, 그런 사람들에게 조금이나마 도움이 되었으면 하는 마음에 글을 작성한다.
Kakao API를 이용하기 위해서는 Kakao에서 제공하는 API Key를 발급 받아야 한다. 본 포스팅에서는 위에서 언급했듯이 해당 과정은 생략하겠다. 혹여나 아직 발급받지 못했다면 검색하면 수도 없이 많은 관련 글이 나오니 해당 글을 참고하여 발급받기 바란다!
내가 기능을 구현하는데 있어서 처음으로 맞이한 관문이었다. 구글링을 해보면 NextJS에서 Kakao API를 이용하기 위해서는 _App.tsx
혹은 _document.tsx
, index.html
과 같은 파일에 Script를 추가하라고 한다. 하지만 우리 팀 프로젝트 폴더를 아무리 찾아봐도 해당 파일들은 찾을 수 없었다. 왜? NextJS 13 버전 부터는 해당 파일들을 지원하지 않는다. 그럼 Script를 어디에 작성해야 하는거지? 바로 layout.tsx 파일이었다. layout.tsx에 아래와 같은 코드를 추가한다.
import Script from "next/script";
export const metadata = {
// 기타 코드 생략 . . .
}
declare global {
interface Window {
kakao: any;
}
}
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<head>
<meta
httpEquiv="Content-Security-Policy"
content="upgrade-insecure-requests"
/>
</head>
<StyledComponentsRegistry>
<body>
<ToasterContext />
<Recoil>
<ReactQuery>
<StyledTheme>{children}</StyledTheme>
</ReactQuery>
</Recoil>
</body>
{/* 해당 부분에 Script를 추가한다. */}
<Script src="https://developers.kakao.com/sdk/js/kakao.js" async />
{/* 이 두번째 Script는 kakao map을 이용하기 위한 Script이다. appkey 부분엔 발급받은 본인의 API KEY를 입력한다. */}
<Script
type="text/javascript"
src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_API_KEY}&autoload=false&libraries=services`}
/>
</StyledComponentsRegistry>
</html>
);
}
위 코드와 같이 나는 layout.tsx의 <body>
태그 하단부에 Script를 추가했다. NextJS에서 제공하는 Script 컴포넌트를 이용하기 위해 이를 import 하여 사용하였는데, 이는 일반 HTML의 script 태그에서는 제공하지 않는 추가적인 기능을 제공한다. 자세한 내용은 NextJS 공식 문서를 참고하길 바란다.
Script 컴포넌트를 이와 같이 추가하고, 또 한 가지 추가해야하는 코드가 있는데 바로 declare global { interface Window { kakao: any; } }
이 부분이다. 나는 이번 프로젝트에서 TypeScript를 사용했기에 해당 코드가 필수적으로 필요했다. 이 코드는 TypeScript의 글로벌 'Window' interface를 확장하여 'kakao' 라는 속성을 추가하는 역할을 한다. 즉, TypeScript에는 기본적으로 'window' 객체에 'kakao' 라는 속성이 존재하지 않으므로, 이를 추가하고 타입은 'any'로 설정하는 것이다. 이 코드를 추가하게 되면 TypeScript에서 'window.kakao'라는 표현식을 사용하여 'kakao' 속성에 접근할 수 있다.
layout.tsx 파일에 Script를 추가했다면, 이제 kakao api를 사용할 준비는 끝났다. 나는 이번 프로젝트에서 MBTI 테스트의 공유하기 기능과 카카오 지도 기능을 사용했는데 우선 공유하기 기능부터 살펴보자.
// kakaoShare.tsx
import { useEffect } from "react";
import Image from "next/image";
const KakaoShareButton = () => {
// 현재 페이지 URL 저장, 이는 공유 버튼 클릭시 열리는 페이지의 주소로 사용됨
const shareUrl = typeof window !== "undefined" ? window.location.href : "";
// useEffect를 이용하여 컴포넌트 렌더링시 카카오 SDK 초기화 및 공유 버튼 생성
useEffect(() => {
if (typeof window !== "undefined") {
const { Kakao } = window;
if (!Kakao.isInitialized()) {
// SDK 초기화 부분, 본인의 API KEY 입력
Kakao.init(process.env.NEXT_PUBLIC_KAKAO_API_KEY);
}
Kakao.Link.createDefaultButton({
// #kakao-link-btn id를 가진 요소에 공유 버튼을 생성하도록 함
container: "#kakao-link-btn",
objectType: "feed",
content: {
title: "맛이슈 MukBTI 테스트",
description: "나와 어울리는 음식은?",
imageUrl:
"https://이미지 url.png",
link: {
mobileWebUrl: shareUrl,
webUrl: shareUrl,
},
},
buttons: [
{
title: "테스트 결과 보러가기",
link: {
webUrl: shareUrl,
mobileWebUrl: shareUrl,
},
},
],
});
}
}, [shareUrl]);
return (
<>
<div>
<Image
// id를 kakao-link-btn으로 설정
id="kakao-link-btn"
src="/images/kakao-talk.png"
width={60}
height={50}
alt="카톡 공유 이미지"
/>
</div>
</>
);
};
export default KakaoShareButton;
공유 버튼 기능을 사용하기 위해 위와 같이 KakaoShareButton 컴포넌트 코드를 작성했다. useEffect를 이용하여 컴포넌트가 렌더링 될 때 카카오 SDK를 초기화 하고, 공유 버튼이 생성된다. 이 때 SDK를 초기화 하는 부분에는 본인이 발급받은 API KEY를 입력하면 된다. 또, useEffect 내에 if문을 이용하여 'window' 객체가 undefined
가 아닐 때 해당 코드가 실행되도록 했다. 그로 인해 'window is not defined' 라는 오류를 방지할 수 있다.
이제 작성한 컴포넌트를 내가 필요한 부분에 사용해보자. 나는 MBTI의 결과 페이지에서 해당 버튼이 필요로 했기에 아래와 같이 코드를 작성했다.
// ResultPageClient.tsx
import KakaoShareButton from "@/app/utils/kakaoShare"; // 컴포넌트 import
// 기타 코드 생략 . . .
return (
<>
<ResultPageLayout className={animation} isDarkMode={isDarkMode}>
{/* 기타 코드 생략 . . . */}
<ShareText isDarkMode={isDarkMode}>테스트 공유하기</ShareText>
<ShareButtonContainer>
<div onClick={copyToClipboard}>
<Image
src="/images/link.png"
alt="링크 공유 아이콘"
width={60}
height={50}
/>
</div>
{/* 컴포넌트 추가 */}
<KakaoShareButton />
{/* 기타 코드 생략 . . . */}
</>
);
};
export default ResultPageClient;
공유 버튼을 사용할 컴포넌트에서 공유 버튼을 import 하고 필요한 부분에 컴포넌트를 추가했다. 그 결과는 ..
성공! 공유하기 버튼도 예쁘게 잘 만들어졌고, 버튼을 클릭해서 카카오톡 로그인 후 다른 사용자에게 공유하면 내가 설정한대로 메세지가 잘 보내지는 것을 확인할 수 있었다.
자, 공유하기를 성공했으니 다음은 카카오맵을 내 페이지에 띄워보자. 지금까지 잘 성공했다면 어려울게 없다!
카카오맵을 사용하기 위해서는 layout.tsx에 Script 코드를 추가해야 하는데, 바로 이 코드이다.
<Script
type="text/javascript"
src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_API_KEY}
&autoload=false&libraries=services`}
/>
위 Script를 추가하면 카카오맵 SDK를 로드할 수 있다. appkey 부분에는 본인이 발급받은 API KEY를 입력하면 된다. 여기서 중요한 부분은 autoload=false
이다. 이는 SDK가 자동으로 로드 되는것을 방지해주는데, 해당 부분을 추가하지 않으면 ..
이런 오류 메세지가 발생하게 되니, 위와 같은 오류 메세지가 출력된다는 해당 부분을 추가해보길 바란다.
Script를 추가했다면, 카카오맵을 만드는 컴포넌트 코드를 작성해보자.
// kakaoMap.tsx
import React, { useEffect } from "react";
import { propsType } from "./landingPage";
const KakaoMap = (props: propsType) => {
useEffect(() => {
if (window.kakao) {
window.kakao.maps.load(() => {
// id가 'map'인 요소에 지도를 생성
const mapContainer = document.getElementById("map");
const mapOption = {
// 해당 좌표는 서울 시청을 중심으로 함
center: new window.kakao.maps.LatLng(37.566826, 126.9786567),
// 줌 레벨 3으로 설정
level: 3,
};
const map = new window.kakao.maps.Map(mapContainer, mapOption);
});
}
}, []);
return (
// id가 'map'인 div 출력, width와 heigth를 설정해줘야 정상 출력됨
<div id="map" />
);
};
export default KakaoMap;
위 코드는 페이지에 카카오맵을 띄우기 위한 가장 기본적이고 기초적인 코드이다. 이는 useEffect를 이용해서 카카오맵 API를 로드하고, 지도를 생성한다. 좌표는 서울 시청을 중심으로 설정되어 있으며 지도 확대 레벨은 기본 3으로 설정되어 있다. 이를 변경할 수 있고, 카카오맵에서 제공하는 라이브러리를 사용하여 카카오맵의 기능을 더 확장시킬 수 있다. 여기서 중요한 것은 return 구문의 div 요소의 width와 height를 지정해주지 않으면 지도가 출력되지 않는다는 점이다.
import React, { useState } from "react";
import KakaoMap from "./kakaoMap"; // 카카오맵 컴포넌트 import
import styled from "styled-components";
const LandingPage = (): JSX.Element => {
// 기타 코드 생략 . . .
return (
<LandingPageContainer>
{/* 기타 코드 생략 . . . */}
{/* 카카오맵 컴포넌트 */}
<KakaoMap searchKeyword={Keyword} />
</LandingPageContainer>
);
};
export default LandingPage;
위에서 작성한 KakaoMap 컴포넌트를 import 하고 필요한 부분에 해당 컴포넌트를 출력한 결과 아래와 같이 정상적으로 지도가 출력되는 것을 확인할 수 있었다.
NextJS 뿐만 아니라 프론트엔드로 참여한 프로젝트가 처음이었고, 오픈 API를 활용하여 기능을 구현하는 것도 처음이었다. 그래서인지 별거 아닌 작업임에도 불구하고 어려움을 겪었지만, 개발자에게 있어서 어려움과 에러는 성장을 위한 과정이 아닌가? 결과적으로 내가 원하는 기능을 구현하였고, 나는 한 단계 더 성장할 수 있었다. 이젠 카카오맵을 응용하여 새로운 기능들을 추가하는 것에 도전해보려 한다.