카카오 지도 연동하기
1. 지도 담을 영역 만들기
2. 실제 지도를 그리는 API 불러오기(라이브러리 다운 받기)
3. 코드 작성하기
Head 컴포넌트를 사용
하면 된다.appkey=
부분에 계정의 JavaScript App Key 값
을 넣어주면 된다.import Head from 'next/head';
export default function index() {
return (
<>
<Head>
<script
type="text/javascript"
src="//dapi.kakao.com/v2/maps/sdk.js?appkey=발급받은 APP KEY"
></script>
</Head>
<div id="map" style={{width:500, height:400}}></div> // 지도 담을 영역
</>
);
}
useEffect
를 이용해서 페이지가 마운트되고 document 객체가 생성된 이후에 카카오맵을 호출할 수 있도록 변경해준다.declare const window: typeof globalThis & {
kakao: any;
};
env
를 이용한 환경변수 설정 등의 방법 등으로 최대한 숨기고, 절대 노출되면 안되는 중요 민감 정보의 경우에는 프론트엔드 서버에 두지 말고 백엔드 서버에 놓고 사용하는 편이 안전하다.버튼을 눌러 이동하는 것은 이미 받아가지고 온 페이지에서 페이지 이동만 하기 때문에 자바스크립트 안에서 화면만 바꿔주는 것으로 서버에 추가적인 요청을 보내지 않아 훨씬 빠르다.
이미 완성된 페이지를 받아가지고 왔다.SPA는 하나의 완성된 페이지 앱이다
지금 문제는 버튼을 눌러 페이지 이동이 워낙 빠른데 카카오 맵 라이브러리를 받아오기 전에 그릴려고 시도하다가 에러가 발생한 것이다.
그렇기 때문에 버튼으로 페이지 이동시 카카오 라이브러리를 받아오고 화면을 그려줌으로써 에러를 해결할 수 있다.
MPA(Multi-Page-Application) 옛날 페이지로 이것은 페이지 이동이 매우 느리다. 버튼 클릭할 때마다 새로고침이 되어 새롭게 페이지를 만들어 보내준다.
SPA(Single-Page-Application) Next.js로 만들고 있다.
첫 랜딩시 frontend서버에서 페이지에 필요한 모든 정보를 넘겨받았고, 페이지 이동 시마다 Browser자체에서 페이지를 나타내거나 감추는 형태로 작동한다 (또한, 이러한 작동방식을 Client Side Rendering:CSR이라 한다..)
a 태그 사용하여 페이지 이동시 CSR(Client-Side-Rendering)이 안되고 페이지 접속을 새로하여 새로운 html을 받아온 것이다.
버튼을 클릭하여 router.push를 하여 CSR이 되어 페이지 이동이 빨라진다.
a태그는 클릭하면 바로 이동이 되지만 문제는 SPA 상태에서 CSR이 안된다.
Link 태그는 a태그와 마찬가지로 클릭하면 페이지 이동이 CSR로 이뤄진다.
그렇다면 어떻게 해야 할까?
**Link 태그**
를 이용하면 된다.**시맨틱 요소**
를 가지고 있는 html 태그로 렌더링이 되기 때문에 웹 표준이나 검색 엔진 최적화 차원에서도 이점이 있다. 그럼 왜 Link 태그 대신 router.push를 사용할까?
1. 버튼을 클릭해서 이동하는게 아닌 경우
- ex) 게시글 등록 버튼 클릭 이후 게시글 등록 함수가 이뤄지고 페이지가 이동되어야 하는데 게시글 등록을 link 태그로 만들게 되면 함수 실행은 되지 않고 페이지 이동만 된다.
2. 페이지 이동시 추가 로직을 실행시켜야 하는 경우
- ex) 마지막 이동 페이지를 globalState에 저장해야 하는 경우
import { useRouter } from "next/router";
import Link from "next/link";
export default function KakaoMapRoutingPage() {
// const router = useRouter();
// const onClickMoveToMap = () => {
// router.push("/29-03-kakao-map-routed");
// };
return (
<div>
{/* <button onClick={onClickMoveToMap}>맵으로 이동하기 !</button> */}
<Link href="/29-03-kakao-map-routed">
<a>맵으로 이동하기 !!</a>
</Link>
</div>
);
}
두 가지 해결책이 있다.
1. 모든 페이지에서 카카오를 받아올 수 있도록 app.tsx에서 script를 통해 kakao맵을 받아오는 방식
2. useEffect를 사용해 직접 다운로드받아 다 받을때까지 기다린 후 그려주는 방식이 있었습니다!
useEffect(()=>{
const script = document.createElement('script'); // <script></script>
script.src="//dapi.kakao.com/v2/maps/sdk.js?appkey=kkkeyy"
document.head.appendChild(script);
script.onload = () => {
const container = document.getElementById('map'); // 지도를 담을 영역의 DOM 레퍼런스
const options = { // 지도를 생성할 때 필요한 기본 옵션
center: new window.kakao.maps.LatLng(33.450701, 126.570667), // 지도의 중심좌표.
level: 3 //지도의 레벨(확대, 축소 정도)
};
const map = new window.kakao.maps.Map(container, options); // 지도 생성 및 객체 리턴
console.log(map);
}
},[]);
createElement
를 통해 script 태그를 직접 만들어 주고, document.head.appendChild(script)
를 사용하여 head 태그에 만들어둔 script를 자식으로 추가한다.script.onload
내부에서 window.kakao.maps.load()
를 통해 카카오 맵 스크립트가 전부 다 받아진 후 화면을 그리도록 해준다.autoload=false
를 붙여 자동으로 불러오는 기능을 꺼주어야 한다.//전체코드
/ 26-02
refetch의 장점은 쉽지만 모든 데이터를 다시 받아와야 하므로 성능적으로 좋지 않다.
useQuery에서 요청이 나갈 때 globalState(현재 사용중인 것은 apollo cache)에 있는지 확인을 하고(fetchPolish) 없으면 백엔드로 요청 하는 것을 cache-first라 하고 무조건 새로운 요청 받아오는 것은 network-only이다.그렇게 받아온 것은 apollo-cache에 먼저 저장된다.
recoilState를 변경하는 것과 마찬가지로 globalState인 apollo-cache-state를 직접 변경할 수 있다면 추가적인 api 요청(refetch)를 보내지 않고 globalState를 직접 바꾸어 수정할 수 있다.
cache 직접수정 : refetch 보다는 어렵고 fetchMore(무한스크롤)와 비슷한 맥락이다. 해야할게 많지만 성능은 더 좋다.
그렇다면 cache 직접 수정만 사용해야하나?
- 그렇지 않다.서비스 규모에 따라 달라진다.
서비스 규모가 작은데 cache 직접 수정하면 복잡하기만 하고 성능 개선에도 도움이 되지 않는다. 하지만 코드 길이가 짧기 때문에 유지보수가 용이해져 효율적이다.
서비스 규모가 크면 refetch되는 것이 많아 api요청이 많이 날아가므로 백엔드에 서버 부하가 걸리는데 이때 cache를 직접 수정하여 성능 개선을 한다.
규모 작을 때 - refetch , 규모 클 때 - cache 직접 수정
정리
게시물/상품 목록과 같은 많은 데이터를 담은 부분에 수정이나 삭제가 발생하여 refetch를 요청하면, 수정/삭제가 발생한 부분만이 아닌 전체 데이터를 refetch하기 때문에 불필요한 네트워크 비용을 소모한다는 단점이 있다.
이를 Apollo의 데이터가 저장되는 cacheState를 직접 수정하여 좀 더 효율적으로 만든다.
추가적인 api 요청인 refetchQueries를 하지 않고 deleteBoard, createBoard에 대한 api 요청 결과 받아와서 이미 저장되어 있는 apollo-cache state(globalState)를 직접 수정한다.
update(cache,{data})
에서 cache는 apollo-cache에 있는 값을 로 가지고 오는 것이고 삭제하고 받은 결과값은 {data}로 들어온다. 가지고온 cache를 수정해준다.
update(cache,{data}){}
를 통해, 기존 데이터가 저장되어있는 cache를 수정한다.(삭제와 등록 로직은 다르다.)
데이터를 추가 또는 삭제 시 update함수의 바디에서 cache.modify({})
를 사용해 cache에 있는 어떤 필드를 수정할지 정한다.
캐시를 직접 수정하기 위해서는 update(){}
라는 기능을 이용하게 된다.
update 기능을 사용할때 파라미터로 데리고 온 cache
는 apollo-cache-state에 있는 global state
이다. 그리고 업데이트 된 결과
는 파리미터의 {data}
에 들어오게 된다.
fields의 prev와 return값
- fields는 캐시에 있는 어떤 데이터를 수정할 것 인지를 알려준다.
- fields 의 prev : 이전데이터를 불러온다.
- fields의 return값 : 이전 데이터를 return 값으로 바꿔준다. 업데이트 된 결과가 {data} 이므로 결국 {data} 내부의 값이 된다.
_id
를 el._id
로 꺼내지 말고 readFiled('_id',el)
로 꺼내온다....
fields: {
fetchBoards: (prev, { readField }) => {
const deletedId = data.deleteBoard; // 삭제된ID
const filteredPrev = prev.filter(
(el) => readField("_id", el) !== deletedId // el._id가 안되므로, readField를 사용해서 꺼내오기
);
return [...filteredPrev]; // 삭제된ID를 제외한 나머지 9개만 리턴
},
},
...
update(cache,{data}){}
를 통해, 기존 데이터가 저장되어있는 cache와 쿼리 실행 이후 받은 데이터가 담겨있는 data를 합쳐준다....
fields: {
fetchBoards: (prev) => {
return [data.createBoard, ...prev];
},
},
...
등록하기 버튼 누르게 되면 실제 백엔드에 요청은 들어가고 원래 백엔드에서 refetch를 하기 때문에 api가 두 번 요청이 되는데 위와 cache-state를 조작하여 create 한 번만 요청하고 받아온 값으로 cache-state를 변경하였다.
유의미한 곳 : 무한스크롤 형태의 페이지네이션을 포함한 대부분
무의미한 곳 : 게시판 (10개씩 끊어서 보여줘야하는 곳)
cache-state -> 최적화 방법
MPA(Multi Page Application)
SPA(Single Page Application)
(re-rendering)
MPA는
전통적인 의미의 홈페이지
이고,
SPA는 홈페이지보다는애플리케이션
의 느낌이 강하다.
writer='철수'
이런 식으로도 할 수 있지만, 주소 안에다가 key value를 포함해서 보낼 수도 있다. 이것을 쿼리스트링(query string)이라 한다.&
로 구분한다.script.src="//dapi.kakao.com/v2/maps/sdk.js?autoload=false&appkey=bb4afdb0f945dc3fc4ed6038257441cb"
el._id
에서 직접 넘겨주는 방법{data}
를 구조분해할당 하지 않고 넣었다면, 예를 들어 update(cache,datas) {const deletedId = datas.data.deletedBoard}
이렇게 써줬어야 한다.