29일차) 카카오 지도를 가져와서 써보자! /Client Side Rendering/멀티,싱글page application을 알아야해/시멘틱 태그/ callback함수, Promise, async-await의 역사까지! Code Camp FE 6기

김아름·2022년 4월 22일
0

코드캠프6기

목록 보기
29/36
post-thumbnail

> 아름짱...체력이 무너저버린날..늘 그렇듯 6시 너머 아침에 구로로 출발하려는 순간 ..
저멀리 오는 버스에 사람이 그득그득한걸 보고 확 스트레스를 받았나보다
버스를 타려는데 위경련이 와서 도저히 탈수 없었고 ㅠ 집들어가서 겔포스랑 위산과다약을 투입했지만 나아지지 않아 꼬부랑 춤을 추면서 9시에 병원가서 링거를 맞아따.....
코캠을 다니면서 많은 정보를 배우고 내걸로 다 만들고 싶은 욕심에 시간이 부족해서 잠을 줄이고 밥을 거르는게 이렇게 체력저하로 나타나 버린것이다 ㅠㅠ
멘토님들이 5.6주차 넘어서 지치지 않도록 체력관리 잘하라고 했던게 이제야.. 체감이 되었따 병원에서 급하게 줌을켜서 듣고 집와서 들었지만 수업은 하나도 내용에 들어오지 않아서

체력을 회복하고

주말을 이용해 다시 수업을 제대로 듣는다!!!!!!!

코캠은 거의 매일 바로바로 수업영상을 수강생들에게 제공한다

수료하고 나서도 영원히 제공해주는것이니 얼마나...이러한 일이 일어났을때 감동적인가..

오늘 배울 내용!

오늘은 지도API 관해서 배웠습니다.


지도API는 크게 구글지도, 네이버지도, 카카오지도 등이 있었습니다. 이들은 크게 비용적인 차이, 세부적인 기능간 차이 등이 있었죠.
그 중 우리는 1일 30만회 무료 요청인 카카오지도를 적용해봤습니다.


지도API를 적용하는 방법은 어렵진 않았습니다!
지도를 적용시키기 전 개발자 등록을 진행하고 애플리케이션을 추가하여
web플랫폼과 도메인을 등록해주었어야 했죠!?
이미 메뉴얼이 잘 만들어져 있기 때문에, 그대로 따라하면 됐었고,
추가적인 샘플도 있기 때문에, 많은 기능을 적용해 볼 수 있었습니다.


하지만, 우리가 기억해야할 중요한 포인트들이 있었습니다!
kakao에 대한 정의! declare window: typeof globalThis & {} 기억 나시죠!
우리는 이 안에 kakao를 넣어주었고 any로 처리해주었습니다!

지도를 넣은 후 Github에 우리의 코드를 그대로 올리면 우리가 발급받은 appkey가 그대로 올라가버린다는 것이였죠! 프론트엔드에서 사용되는 appkey는 숨길 수 없었습니다!
그렇기에 appKey 요청을 받아줄 도메인을 적어줘야 합니다.
-> 즉, 우리가 지정한 도메인이 아닌 곳에서는 appkey가 작동하지 않도록 설정해주었습니다!
이 부분을 기억해 주세요! 이후에 우리가 배포를 진행하고 도메인이 만들어지면,
카카오맵에도 적용해 주어야 합니다.


페이지 이동에 있어 문제가 있었죠, 브라우저에서 router.push로 이동할 때, 카카오 기능이 로딩되기도 전에 실행되어 문제가 발생했습니다.
이 문제는 a태그를 통한 이동에서는 발생하지 않았습니다!
이를 이해하기 위해서는 MPASPA에 대한 이해가 필요했습니다!


a태그는 해당 페이지를 새롭게 다시 요청하는 것이였죠!
즉, 클릭 시 마다 새롭게 페이지를 만들어 보내주는 것이였죠!
이런걸 우리는 MultiPageApplication라 한다 했습니다!


반대로 우리가 사용하는 NEXT의 SinglePageApplication는 어땠죠!?
첫 렌딩에서 frontend서버에서 페이지에 필요한 모든 정보를 주었고,
페이지 이동 시마다 Browser자체에서 페이지가 나타나고 감춰지는 형태로 작동한다 했습니다!
-> 이러한 작동방식을 Client Side Rendering이라 했습니다
따라서, kakao 기능이 로딩이 완료될 때까지 기다려주는 작업이 필요했습니다.


이를 위해, 두가지 해결책이있었습니다!
모든 페이지에서 카카오를 받아올 수 있도록 app.tsx에서 script를 통해 kakao맵을 받아오는 방식과,
useEffect를 사용해 직접 다운로드받아 다 받을때까지 기다린 후 그려주는 방식이 있었습니다! 전자의 방식은 비효율적이기에 우리는 후자방식을 사용하였습니다!


우리가 직접 createElement라는 기능을 통해서 script 태그를 만들어 주고,
document.head.appendChild(script)를 사용하여 head 태그에 넣어주는 방법이였죠!
이후, script.onload 내부에 window.kakao.maps.load()를 통해 카카오 맵이 전부 다 받아 진 후 화면을 그려주게 해주었죠! 여기서 중요한 부분이 있었습니다 카카오 script부분의 뒤에 autoload=false를 붙여 자동으로 불러오는 기능을 꺼줬어야 했습니다!
router.push와 Link 의 방식도 잠깐 알아봤습니다!
Link를 사용하여 a태그를 사용하면 router.push와 같은 동작을 하되, 검색 봇이 알아볼 수 있는 시멘틱 태그의 요소까지 갖출 수 있다고 했습니다! 꼭 기억해 주세요!


위 포인트들만 기억해 주신다면, 지도를 구현하시는데는 크게 어려움이 없을 겁니다!


지도 내용을 중고마켓 Backend와 연결하기 위해서는 createUseditemAPI에 useditemAddress 부분이 있습니다.
여기에 lat, lng 부분을 이용해 주시면 됩니다!
콜백함수에 대해서도 알아봤죠!
함수의 인자로 들어가는 함수를 콜백함수라 헀습니다! 대표적인 예로 useEffect(),setTImeout()이 있었죠!


콜백함수는 함수의 기능이 끝난 이후 내가 넣은 함수를 실행시켜주려 할 때 사용한다 했습니다!
우리는 더 정확한 이해를 위해 실습을 통해 알아봤죠! aaa(myfunction) 기억나시죠!?


callback이후에 나온 Promise도 알아봤습니다! Promise는 비동기 작업이나 조금 오래걸리는 작업들에 쓰인다고 했죠?
Promise를 사용하면 callback지옥을 해결할 수 있었지만 직관적이지 못하다는 단점이 있었습니다!


이 모든것을 해결하기 위해 나온 것이 async-await였습니다! 실습을 통해서 본 결과, 직관적이고 깔끔하며 작성 순서대로 하나씩 실행되었죠!

오늘 배울 내용들 !


-네이버 구글 카카오등등..개발자 전용 사이트가 있었네!
-카카오 개발자 사이트에 가입해서 내 애플리케이션 추가해보자(폴더라고 생각)
https://apis.map.kakao.com/
카카오 maps API! 웹과 앱에 지도를 넣을수 있도록 제공한다

한국어로 되어있기 때문에 독스보기도 편하고 많은 기능들이 들어있다!
갓카오!


api가이드에 나와있는 순서 그대로~ 하면 카카오 지도를 사용할수 있다 !
head에 추가하면 스크립트를 먼저읽고 아래를 그리고
바디(script)는 몸통을 먼저 그리고 불러오게찌
우리는 head에 추가 next.js쓰고있기 때문에
import Head from 'next/head'
import Script from 'next/script'

이거 해조야댐 다운받을때 window.kakao가 생기는거라서
declare const window; typeod globalThis & {
kakao: any;}

window.kakao가 있는거야! 라고 말해조야댐


카카오 지도 보여주기 코드

import Head from "next/head";
// import Script from "next/script";
import { useEffect } from "react";
declare const window: typeof globalThis & {
  kakao: any;
};
export default function KakaoMapPage() {
  useEffect(() => {
    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); 
    // 지도 생성 및 객체 리턴
  });
  return (
    <>
      <Head>
        <script
          type="text/javascript"
          src="//dapi.kakao.com/v2/maps/sdk.js?appkey=733d0a29ec73b8803266c00fc97055a5"
</script>
      </Head>
      {/* <Script src=""/> */}
      <div>
        <div id="map" style={{ width: "500px", height: "400px" }}></div>
      </div>
    </>
  );
}```

잘 나오는데 왜 다른 페이지에서 버튼태그로 이동하면 안나올까?
(a href 태그는 잘나옴 ! )


-> 클라이언트 사이드 렌더링
-> 브라우저 페이지이동 요청이 있을때마다
서버에 가지 않고 클라이어트 페이지에서 페이지를 변환하는것
(react의 방식. 각각의 싱글페이지를 보여줌) -> spa(싱글페이지어플리케이션)
->거대한 한 페이지 안에서 다 받아온다음에 클릭된 일부분만 보여주는 형식이다
성능이 빠르긴하지만, router.push를 이용해서 클라이언트 사이드렌더링으로
이동하려 하니까 useeffct로 먼저 그릴때, 프리젠터의 head부분에 있는 src 없는 상태에서 그리려 하니까 kakao map을 찾지 못하는것이다
a 태그는 해당 페이지 서버에 접속해서 받아온다음에 그리기 때문에 가능했던 것


반대개념 -> mpa(멀티페이지어플리케이션)
-> 새로고침할때마다 다시 받아오는고


이 문제점을 보완하고자 nextjs에서 제공해주는 link태그를 쓰면 저 코드에서
router.push를 써서 함수를 만들어준 부분을 쓰지 않아도 된다!

^ 이렇게 link태그 안에 쓰면 된다 !
클라이언트 사이드 렌더링을 원하면 link태그 ! (직방같은 빠른곳)
사실 얘는 a태그 바꿔서 보여줘라 라는 의미 (?)
보여지기 위해 쓰는거고 사실은 가짜 a라서 큰 의미는 없다 ..
근데 왜쓰냐?!


링크태그는 시멘틱 요소(태그에 의미를 담아주는것)가 있어서 검색봇한테 알려주는게있어!

의미를 가진 태그들을 활용해서 검색봇들이 보여주는게 다르다 !
(다른 사이트를 검색봇들이 돌아다니면서 코드를 읽을때 의미를 알게하기 위해서)
(위의 예는 나의 장터라는것을 검색봇에게 꼭 알려주고 싶은 정보라서 검색엔진이 a태그니까 페이지 이동하는거구나! 두 페이지가 연관이 있는거구나 ! 라고 알게 해주는것이다.
검색엔진은 router.push같은게 있는지 모른다..! 검색봇은 프리젠터의 태그들을 읽으면서 검색기능을 올리는것이기 때문에 )
검색어 순위가 올라가고 내려가고 봇들이 보여주는게 저러한 기준이다 !
router.push까진 못 읽고 함수와 큰 틀 과 받아야하는 페이지 정도 읽어주는것

CSR(클라이언트 사이드 렌더링), SPA(싱글페이지 어플리케이션)이 중요한가요?

네 ! 그래서 리액트 앵귤러 뷰에서 엄청나게 발전을 했기 때문에 !
-> 그래서 SPA형식의 페이지와, MPA형식의 페이지를 잘 봐보면 로딩 시간과 횟수에 차이가 있다 !


-스크립트 자체를 이 전부터 받아놓는 방법 (app.tsx)
(작동은 가능하나 모든 페이지에서 필요없는 지도를 다운받을 필요는 없으니 하지 않을것이다 )
-직접 페이지에 스크립트 태그를 만들어서 head의 script에 src를 넣어주기
캑체에 키와 벨류를 몇개씩 각각 보내고 싶을때 쿼리스트링
지금 이 상태는 서버사이드렌더링 때문에 안그려지는 상태!
useEffect 빈곳에 다시 써보자


1. 컨테이너에서 스크립트 태그만들고
2. 다운로드 받고
3. 그리고 프리젠터를 실행하도록 !


const script = script라는 태그를 만들어주고,
script.src = 스크립트태그의 src를 저장해주고
document.head.appendChild~ = html의 head부분으로 가서 자식을 추가해줄껀데 (script)라는 애를 추가해준다
script.onload = 스크립트가 로드가 되면, 그러면 이제 실행하자 ! 라고 작성을 해준 부분이다


그런데, 카카오맵 docs에 들어가보면, 친절하게 설명이 되어있다/

  • 스크립트를 동적으로 사용하기 위해
  • 스크립트의 로딩이 끝나기전에 v3 객체에 접근하면 에러가 발생하기 때문에, 로딩이 끝나는 시점에 콜백을 통해서 객체에 접근할 수 있도록 해주세요!
  • 비동기 통신으로 페이지에 v3지도를 넣을때 사용합니다
  • 로딩 스크립트 주소에 &기호를 붙여서 ""안에 같이 autoload = false로 지정해주세요
  • ^ 이 주소로 객체를 보내고 싶을때 쿼리스트링으로 보내고 싶을때 키, 벨류, 키, 벨류로 보내는 방법이다 !
  • 스크립트 다운로드 받고,카카오 map이 로드가 되면, 그때 html에 있는 map 객체에 접근을 해서 그려주자
  • 아무리 빨리 클라이언트 사이트를 들어간다 하더라도, 맵이 다 그려지고 다운받도록 하기 때문에 맵이 안그려질일은 없다 !

    이렇게 까지 이해하고 작성해주면 카카오 맵 이해완료 !
    그러면 이제 마커를 추가한다던지, 하는 기능들을 이렇게 추가해서 쓸수 있다 !

- 콜백함수

시작은 콜백, 콜백에 문제가 생겨서 promise의 등장, promise에 문제가 생겨서 async,await가 등장한것이다.
-> 좀 더 깊게 코드를 이해하려면 그 전 과정을 다 이해해야한다 가보자!

함수 aaa()안에 들어가는 애 qqq를 파라미터 매개변수라고 한다
aaa()안에 실제로 들어가는 "안녕하세요"를 argument라고 한다.

콜백함수는 사실 함수의 인자를 함수로 넣는것일뿐 !

내가 특정 로직을 보내줄테니깐, 너가 로직을 실행시켜줘!

map할때도 저 콜백함수 형식을 봤었고, settimeout할때도 봤었다.
우리는 간단하게

const result = await.axios.get("")
console.log("받아온 result")

이렇게 api요청해서 받아온 데이터 기다려서 쓸수 있었는데
-> async가 없을때 콜백함수를 썼었어!
aaa가 요청해서 데이터를 받아오는 함수라고 해봤을때,

밑에 쓴부분은 aaa가 받아온거로 실행시키는 부분이다
나 이부분이 제대로 구조가 이해가 안갔었는데 .
aaa(qqq) aaa함수에 매개변수로 qqq라는 함수가 들어간거고, 그 함수를 밑에서 알려주는거고, aaa에서 나온 result로 qqq를 실행해주는거다 !

함수 안에 인자로 함수를 넣어주고 (콜백함수) 비동기적인 작업을 동기화 해줬다 ( 모두 한꺼번에 실행해야하는거를, 얘만 기다리고 실행하게 할 수 있도록 )

-> 즉 , 콜백함수를 통해 비동기적인 작업을 동기화 해줬다.

이 콜백함수의 문제는 뭘까?
랜덤 숫자를 받아오는 예시를 들어보면

  • "get", 뒤에는 restapi의 주소이다
  • axios와 비슷한 방식으로 api요청을 get방식으로 요청하는것
  • send - 요청을 한다
  • addEvent("load", 콜백함수)- 요청이 끝나면 콜백함수 실행시켜줘 !
  • load는 첫번째 인자, 함수가 두번째인자가 되는것이고
    받은 데이터로 함수를 실행한다는것 !
  • 그래서 콜백 함수에 num에 그 숫자를 담아주었다.
    ->그리고 그 숫자를 기반으로 해당하는 게시글 조회와 ,
    유저 아이디가 쓴 글목록 조회를 해보자!
  • 그러면 다시 그 함수안에, XMLYttpRequest가 들어가야한다.( 얻어온 숫자를 가지고, 다른 Restapi사이트를 가서, 요청을 해야하니까 !)

    ^그 안에 다시 게시글 조회 쿼리 넣어준 모습
    -> 그러면 이제 저기 res.target.response.UserId가 그 게시글을 쓴 유저의 id가 담기는거지 !
  • 다시 그 아이디를 가지고 , XMLYttpRequest요청해서 그 아이디의 게시글을 조회하는 모습..

    이렇게 콜백에서 연속되는 콜백..지옥에 갇히면서,,,
    최종 결과값을 이렇게 힘들게 얻어야 하나 ?!
    이렇게 콜백함수의 문제가 생겨서, 나온것이 바로

- Promise

promise는 외부 api요청을 하는등 시간이 걸리는 요청이 있을때 사용한다
axios는 promise로 만들어진것이다
axios라는 라이브러리의 return타입으로 promise가 나온다

  • promise.then() - 결과가 성공했을때 받는 부분
  • promise.catch() - 실패했을때 받는 부분
    axios안에 promise 로직을 직접 만드는 예를 통해 살펴보자

    -> promise로 무엇을 받을수 있는가?
  • 성공했을때는 resolve, 실패했을때는 reject를 받을수 있다.
  • 그렇게 받은 데이터를 promise.뒤에서 받아주면 res에는 "철수"가 담기고, err에는 "에러발생!!!"이 담기게 된다
    axios는 promise를 반환한다고 했지?
    axios는 그래서 이런형식으로 만들어져있다

    resolve해주면 .then으로 반환하는...!
    axios.get이라는 함수안에서 반환하면, .then으로 결과를 받아온다는 말이다 !
    그래서 이렇게 간편하게 axios와 .then으로 쓸수 있게 된 것

    -> promise는 콜백과는 다르게 .then을 연달아서 쓸수 있다
    밑에는 똑같이 랜덤 번호 받아오기 / 그 번호 게시물 조회하기 / 그 게시물의 유저아이디 받아오기 / 그 유저아이디의 게시글 조회하려면 이렇게 계속 .then으로 데이터를 받아와야겠지 ?
    콜백처럼 안으로 들어가진 않지만,
    얘는 계속 내려가네 ?!
    promise chaining(프로미스 체이닝) 이라고 한다


async와 await로 써보자 !

얘는 아무데서나 쓸수 있는게 아니야,
promise를 await해야한다
await는 promise만 기다릴수 있다
(비동기라고 해서 다 await를 쓸수 있는건 아니다)
(axios같은 promise를 리턴하는 애들에게 쓸수 있는데, 요즘 나온애들 Fetch...등 다들 promise를 리턴한다 ! )
-> await는 그 작업이 끝나서 데이터를 받아올때까지 밑으로 내려가지 않는거니까 ! 순서대로 받아오자! 라고 적어만 주면 되겠지 ?
그래서 우리가 여지껏 async와 await를 쓴것이다 !

간~~ ~ ~~단 !


promise를 쓸때 주의할 점 !?

여기서 1,5,2,3,4로 나오는이유는
큐로 들어가기때문에,
(promise도 비동기작업이라 백그라운드로 들어가서 먼저 실행안되고,)
axios실행되기 때문에 (이벤트루프 다시 이해하자)
-> 실수가 많이 나는 부분이다


async와 await는 위에가 끝나야 아래를 실행하게하니까
명확하니까 이런문제도 없어서, 우리가 쓰고 있는것이다 !

  • 그러면... 지금 우리가 본, promise가 들어가는 큐와, settimeout같은 애들이 들어가는 큐는 같은 큐일까?

Event Loop With Queue


promise와 settimeout과 setinterval이 어떻게 실행되는지 보기 위해 중간에 딜레이도 걸어보고, 큐도 직접 넣어보았따.


이벤트루프에서는 백그라운드에서 처리가 되러 들어올때
같은 테스크큐에 들어가는것이 아니라,
테스크큐는 세분화되어있어서 각자 해당하는곳에 들어가게된다.

setTimeoutrhk setInterval은 매크로 태스크 큐에 들어가게 된다

Promise는 마이크로 태스크 큐에 들어가게 된다


그럼 저기서 큐가 여러개면 어떻게 어떤 순서로 빠지게 되는거지 ?
-> 마이크로 태스크 큐가 먼저 다 나오고, 매크로 태스크 큐가 나오게 된다 !


그럼 여기서 순서를 봐보면,
1. setTimeout이 들어가고 (매크로 태스크 큐에)
2. Promise가 들어가고 (마이크로 태스크 큐에 )
3. setInterval이 들어가고(매크로 태스크 큐에)
4. 딜레이 반복문 실행되고있고
5. 새로운 promise가 들어간다 (마이크로 태스크 큐에 )

1. 큐에 들어가지 않는, 시작과 끝 콘솔이 찍혀나오고
2. 먼저 들어간 순서와 상관없이 마이크로 큐에 먼저 들어간 애가 다 나오고
3. 매크로큐에 있는 것들이 나와서 실행된다

세분화 된 큐의 원리를 이해하고 이벤트 루프 개념을 잘 잡아두자!

  • 기절하느라... 풀어보지 못한 알고리즘 문제와,
    듣지못한 알고리즘 수업은
    반드시 놓치지 않고 따라가길 다짐...! 아름 !!!!!!!!!
profile
SUNNY SUMMER ! 같이 일하고 싶은 개발자 여름이의 초심을 잃지 않기 위한 주절주절 부트캠프 시절 블로그.

1개의 댓글

comment-user-thumbnail
2022년 11월 4일

API key 공개되어 있네요..
도용 가능성이 있기에 해당부분 모자이크 하시는것이 어떻지요 ㅜ..

답글 달기