Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AUD-7] T Map SDK 활용을 위한 TMapModule 및 useTMap Hook 제작 #4

Merged
merged 10 commits into from
Jan 18, 2024
1 change: 1 addition & 0 deletions .env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_TMAP_APP_KEY=
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ dist
dist-ssr
*.local

.env

# Editor directories and files
.vscode/*
!.vscode/extensions.json
Expand Down
21 changes: 11 additions & 10 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>여행 지도 계획 플래너, 어디 (Audy)</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>여행 지도 계획 플래너, 어디 (Audy)</title>
<script src="https://apis.openapi.sk.com/tmap/vectorjs?version=1&appKey=%VITE_TMAP_APP_KEY%"></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"devDependencies": {
"@tanstack/react-query-devtools": "^5.17.10",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/node": "^20.11.5",
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@typescript-eslint/eslint-plugin": "^6.14.0",
Expand Down
39 changes: 22 additions & 17 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 50 additions & 8 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,57 @@
import { Route, Routes } from 'react-router-dom';
import { useState } from 'react';

import LoginPage from './pages/LoginPage';
import RedirectionPage from './pages/RedirectionPage';
import reactLogo from '@/assets/react.svg';
import { useTmap } from '@/hooks/useTmap';

import viteLogo from '/vite.svg';

import './App.css';

function App() {
<Routes>
<Route path="/" element={<LoginPage />} />
<Route path="/redirect" element={<RedirectionPage />} />
</Routes>;
const [count, setCount] = useState(0);

Check warning on line 11 in src/App.tsx

View workflow job for this annotation

GitHub Actions / pr-check

'setCount' is assigned a value but never used

const { tmapModuleRef, mapContainerRef } = useTmap({
mapId: 'tmap',
latitude: 37.5652045,
longitude: 126.98702028,
});

const handleTestAddMarker = () => {
if (!tmapModuleRef.current) return;
console.log(tmapModuleRef.current);
tmapModuleRef.current.setMarker({latitude: 37.56520450, longitude: 126.98602028});

}

return <LoginPage />;
return (
<>
<div>
<div ref={mapContainerRef} />
<a href="https://vitejs.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img
src={reactLogo}
className="logo react"
alt="React logo"
/>
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={handleTestAddMarker}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
);
}

export default App;
31 changes: 31 additions & 0 deletions src/hooks/useTmap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useEffect, useRef } from 'react';

import { TMapModule, type TmapConstructorType } from '@/utils/tmap';
Comment on lines +1 to +3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기 중간에 공백있는건 import 정렬 플러그인이 자동으로 띄워놓은건가요 ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그렇습니다. 정렬 기준은 AUD-02 PR에서 확인 가능하세요


export const useTmap = ({
Copy link
Collaborator Author

@RookieAND RookieAND Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

T Map 을 렌더링하려는 HTMLDivElement 가 렌더링 된 이후 모듈을 생성하기 위해 Hook 을 도입했습니다.
useEffect 를 사용하지 않고 컴포넌트 단에서 TMapModule 클래스 인스턴스를 생성할 경우, 렌더링 이전에 Map 을 주입하려고 시도하여 에러가 발생합니다.
리액트 컴포넌트의 LifeCycle 과 최대한 패턴을 맞추기 위해 고안된 방법입니다.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

설명 감사합니다 ~! 좋은 방법이네요

mapId = 'tmap',
width = 640,
height = 480,
zoom = 10,
latitude,
longitude,
}: TmapConstructorType) => {
const mapContainerRef = useRef<HTMLDivElement | null>(null);
const tmapModuleRef = useRef<TMapModule | null>(null);

useEffect(() => {
if (!mapContainerRef.current) return;

mapContainerRef.current.id = mapId;
tmapModuleRef.current = new TMapModule({
mapId,
width,
height,
zoom,
latitude,
longitude,
});
}, [height, latitude, longitude, mapId, width, zoom]);

return { mapContainerRef, tmapModuleRef };
};
8 changes: 1 addition & 7 deletions src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { StrictMode } from 'react';

import { createRoot } from 'react-dom/client';

import App from './App.tsx';
import './index.css';

createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
);
createRoot(document.getElementById('root')!).render(<App />);
14 changes: 8 additions & 6 deletions src/types/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
// SVGR Plugin NameSpace
declare module '*.svg' {
const svg: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
export default svg;
}

// T-MAP API NameSpace
declare global {
interface Window {
Expand All @@ -12,3 +6,11 @@ declare global {
Tmapv3: any;
}
}

// SVGR Plugin NameSpace
declare module '*.svg' {
const svg: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
export default svg;
}

export {};
46 changes: 46 additions & 0 deletions src/utils/tmap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export interface TmapConstructorType {
/** 지도를 렌더링할 HTMLDivElement 에 적용할 id */
mapId?: string;
/** 지도 Element 의 width (px) */
width?: number;
/** 지도 Element 의 height (px) */
height?: number;
/** 지도 Element 의 확대 정도 (1 ~ 15) */
zoom?: number;
/** 지도 의 중심점 위도 */
latitude: number;
/** 지도 의 중심점 경도 */
longitude: number;
Comment on lines +11 to +13
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다른 것들도 옵셔널이면 얘네도 그냥 기본값 줘도 되지 않을까요? 뭐 서울시청 이런식으로 해서

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

중심좌표 값이 없을 경우에는 내부적으로 어디를 기본으로 바라볼지만 얼라인 맞추면 좋을거 같습니다

}

export class TMapModule {
#mapInstance: typeof window.Tmapv3;
Copy link
Collaborator Author

@RookieAND RookieAND Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추후 이 mapInstance 를 기반으로 TMap API 를 활용하도록 메서드를 작성해주시면 됩니다.
제가 예시로 작성한 마커 추가 로직의 경우 아래와 같습니다 (참고차 제공드립니다)

export class TMapModule {
    #mapInstance: typeof window.Tmapv3;

    // 지도에 생성된 마커들을 보관하는 배열 markerList (private)
    #markerList: (typeof window.Tmapv3.Marker)[] = [];

    constructor({
        mapId = 'tmap',
        width = 640,
        height = 480,
        zoom = 10,
        latitude,
        longitude,
    }: TmapConstructorType) { ... 중략 }

    // Map Instance 에 새로운 마커를 추가하는 메서드 setMarker
    setMarker({
        latitude,
        longitude,
        iconUrl,
    }: {
        latitude: number;
        longitude: number;
        iconUrl: string;
    }) {
        const marker = new window.Tmapv3.Marker({
            position: new window.Tmapv3.LatLng(latitude, longitude),
            iconUrl,
            map: this.#mapInstance,
        });

        this.#markerList = [...this.#markerList, marker];
    }
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

참고하도록 하겠습니다!


constructor({
mapId = 'tmap',
width = 640,
height = 480,
zoom = 10,
latitude,
longitude,
}: TmapConstructorType) {
if (typeof window === 'undefined') {
throw new Error('T Map 은 Server Side 에서 사용할 수 없습니다.');
}
Comment on lines +27 to +29
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (!window)로 하지 않고 명시적으로 undefined로 하신 이유는 null일 때와 undefined일 때가 다른 상황이라서 그런건가요?

Copy link
Collaborator Author

@RookieAND RookieAND Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 코드가 서버 단에서 실행될 경우에는 window 변수가 별도로 Global Context 에 존재하지 않습니다.
ReferenceError 가 발생할 수 있기 때문에 typeof 연산자로 이를 에러 없이 안전하게 체크하기 위함입니다.

실제로 NodeJS 에서 아래 코드를 실행하면 이런 에러가 발생합니다.

if (!window) {
    console.log('it is Node Rumtime')
}

111

하지만 typeof 로 코드를 작성하면 이러한 에러 없이 정상적으로 실행됩니다.

if (typeof window === 'undefined') {
    console.log('it is Node Rumtime')
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

설명 감사합니다 !


const mapElement = document.getElementById(mapId);

if (!mapElement) {
throw new Error(
'T Map 을 렌더링하기 위해 필요한 HTMLDivElement 가 없습니다.',
);
}

this.#mapInstance = new window.Tmapv3.Map(mapId, {
center: new window.Tmapv3.LatLng(latitude, longitude),
width: `${width}px`,
height: `${height}px`,
zoom,
});
}
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

Expand Down
Loading