개발자
류준열

하이빌리지 : 위치기반 가까운 관광지 보여주는 서비스

위치기반 가까운 관광지를 보여주는 서비스를 만들었다.

만든 이유

주말에 어디 놀러갔다 오고 싶어서 구글에 여행지를 검색하면 티스토리 광고글이 가장 상단에 있는 경우가 많다.

'시각적으로 한눈에 가까운 관광지를 볼 수 있으면 좋겠다' 라는 생각에 만들어보았다.

하이빌리지

기획

요구사항은 간단하다.

  • 근처 관광지를 한눈에 보여준다.
  • 지도를 드래그해서 그 외 지역도 검색해볼 수 있다.

지도는 경험이 있는 카카오맵을 선택했고, api는 관광공사에서 제공하는 tour API를 사용했다.
관광정보[국문] api 명세는 이 페이지 이다.

api 문서

겪었던 문제

여러 사소한 문제들을 겪었지만, 나에게 가장 도움이 된 문제는 렉시컬 환경과 관련된 문제다.

이 문제를 해결하면서 렉시컬환경을 고려할 수 있는 안목을 갖게 되었고, 회사에서도 버그의 원인이 렉시컬 환경임을 알아볼 수 있었다.

간단히 작성하면 다음과 같다.

const Component = () => {
    const [count,setCount] = useState(0)
    useEffect(()=>{
        ... 
    },[count])
    
    useEffect(()=>{
        // count 3으로 만들었는데 왜 0이 찍히지?
        return ()=>{console.log(count)}
    },[])
    
    return (
    <>
      {count}
      <button onClick={() => setCount(count + 1)}>count++</button>
      <button onClick={() => {navigate("/")}}>page go</button>
    </>
  );
}

localhost3000

이 컴포넌트에서 count를 3으로 만들고 언마운트를 시키면 console이 3이 찍힐것이라고 예상했는데 0이 찍혔다. 렉시컬환경 때문이다.

자바스크립트에서 new Function으로 만든 함수를 제외한 모든 함수는 클로저이다. 따라서 함수 컴포넌트도 클로저다.

클로저는 호출될 때마다 렉시컬 환경을 생성하고 클로저의 모든 참조는 호출될 때 생성된 렉시컬 환경안에 기록되어 있다.

   const [count,setCount] = useState(0)
   ...
    useEffect(()=>{
       // 왜 3이 아니라 0이 찍히지?
       return ()=>{console.log(count)}
   },[])

정리하면

  1. 위 useEffect callback은 첫 렌더링때만 실행된다.
  2. 렉시컬 환경도 첫 렌더링때만 생성된다.
  3. count는 첫 렌더링때 생성된 렉시컬 환경에 0으로 저장된다.
  4. 언마운트를 위해 clear함수를 실행시킬때는, 렉시컬 환경에 저장된 count = 0 을 가져온다.
  5. 유저 인터랙션에 의해 count가 어떻게 변하던, useEffect callback 내의 count는 초기값 0 이다.

새로 시도해 본 것들

개인 컴포넌트 라이브러리

라이브러리에서 임포트한 컴포넌트 개수는 3개인데, 고작 3개를 위해 라이브러리를 사용하는 건 성능에는 좋은 것 같지 않다. 라이브러리의 용량에 비해 실제로 사용한 컴포넌트의 양은 적은데 이게 다 불필요한 JS 번들이기 때문이다. 라이브러리 번들 사이드

하지만 성능과 별개로 내가 만든 컴포넌트 라이브러리가 실사용에 불편한 지점들을 발견할 수 있었다.
범용적인 컴포넌트를 만드는 고민을 했는데 외부 class로 원하는 스타일을 주입할 수 있게 수정했다.

export const Button =({...,className,...props}) => {
  return <button className={{...,className}}}>...</button>

컴포넌트 활용

vite로 마이그레이션

webpack은 코드 변경이 있을때마다, 처음부터 다시 번들링을 하는데, vite는 수정된 부분만 업데이트 한다. 프로젝트가 클수록 이점이 크다고 하다. 물론 이 프로젝트에는 별 차이가 없다. 연습삼아 해본것에 의의를 둔다.

테스트코드

시작할때 TDD 방법론으로 개발하진 않았지만 뒤늦게 테스트코드를 추가하고 있다. 외부 라이브러리인 kakao map을 test 환경에서 만들 수 없어 관련된 모든 기능을 모킹해야했다.

가상돔에서 특정 element들을 create하고 remove하는 방식으로 작업했다. (커밋)

테스트코드 cli

유저 플로우

심플하다.

  1. 처음 들어왔을떄는 현재위치를 받는다. 유저플로우1-현재위치확인
  2. 지도를 그린다.
  3. 위치주변의 관광지를 검색하고 지도에 마커를 그린다.유저플로우2,3-지도,마커 그리기
  4. 지도를 드래그 하면 변경된 지도의 중심위치 반경 관광지들을 검색하고 또 마커를 그린다. 유저플로우4-지도 드래그하면 3재실행
  5. dropdown을 통해 검색 개수, 검색 반경을 변경할 수 있다. 드롭다운용

결론

실제로 주말에 이거 보면서 동대문, 월미도, 아라타워 전망대 갔다왔다. 가족들에게도 알려주었는데, 실제로 써볼련진 모르겠다.

sitemap도 안달았는데 누가 쓸지는 모르겠고, 내가 나의 문제를 해결한 것에 의의를 둔다.