기록하는 개발자

[React] React에 naver-map api 적용 도전기 본문

Web/React

[React] React에 naver-map api 적용 도전기

밍맹030 2022. 1. 7. 16:20
728x90

지도를 사용하는 프로젝트를 하게되어 naver map api를 사용하기로 했다.

api 를 처음 적용해봤기도 하고 react로 본격적인 팀프로젝트도 처음이라 쉽지 않았다.

구글링을 해도 일반 <script>태그로 작성하는 예시는 많았지만

react에 작성하는 예시는 너무 없어서 맨땅에 헤딩하는 느낌이었다..

아직 부족해서 코드가 지저분할지라도 동작은 하기 때문에

react 프로젝트에서 naver map을 사용하는 사람들에게 조금이라도 도움이 되길 바란다.

 

naver map 회원가입이나 key값을 받아오는 설명은 검색하면 너무 자세히 나와있어서 생략하겠다.

+) key 값은 env. 파일을 만들어 관리하자,,

 

나는 Home 아래와 같이 화면에 지도를 띄우고 도로명 주소를 검색하면

해당 좌표로 이동하여 화면이 줌 되고, 마커를 찍어주도록 구현하고자 하였다.

첫 화면 zoom level=12&nbsp;
서울 시청 주소를 검색한 후 화면 zoom level=15

 

<NaverMapApi.js>

import React, { useState } from "react";
import { RenderAfterNavermapsLoaded, NaverMap, Marker } from "react-naver-maps";

export const NaverMapAPI = (props) => {
  return (
    // 검색을 하고싶은 경우 submodules 로써 geocoder를 꼭 추가해줘야한다.
    <RenderAfterNavermapsLoaded
      ncpClientId={process.env.REACT_APP_API_Client_ID}
      submodules={["geocoder"]}
    >
      // 부모 컴포넌트(Home.js)로부터 받은 props를 이용해 NaverMap api 호출
      <NaverMap
        mapDivId={"maps-getting-started-uncontrolled"}
        style={{ width: "100%", height: "100%" }}
        center={{ lat: props.Latitude, lng: props.Longtitude }}
        defaultZoom={12}
        zoom={props.zoom}
        minZoom={12}
        enableWheelZoom={false}
      >
        // prop.zoom이 15인 경우는 주소 검색이 실행되었을 때이므로 maker를 표시해준다.
        {props.zoom == 15 && (
          <Marker
            position={{ lat: props.Latitude, lng: props.Longtitude }}
            title={props.roadAddress}
            clickable={true}
          />
        )}
      </NaverMap>
    </RenderAfterNavermapsLoaded>
  );
};

export default NaverMapAPI;

<Home.js>

import React, { useState, useEffect } from "react";
import "../static/home.css";
import NaverMapAPI from "../components/NaverMapAPI";

const Home = () => {
  const { naver } = window;
  
  // 주소 검색 함수에 넘겨줄 address 상태 관리
  const [address, setAddress] = useState("");
  const [roadAddress, setRoadAddress] = useState(null);

// 변경 가능성이 있는 경도, 위도, zoom을 useState hook을 이용하여 상태 관리 한다.
  const [lat, setLat] = useState(37.54);
  const [lng, setLng] = useState(126.99);
  const [zoom, setZoom] = useState(12);

//주소 검색 시, 주소창의 change event를 감지한다.
  const handleChange = (e) => {
    const { address, value } = e.target;
    const newAddress = { address: value };
    setAddress(newAddress);
  };

//주소 타이핑 후 검색 버튼을 누르면 동작하는 함수
  function searchAddressToCoordinate(address) {
    //geocode에 입력받은 address를 query로써 전달
    naver.maps.Service.geocode( 
      {
        query: address,
      },
      function (status, response) {
        // 문제 발생할 경우
        if (status !== naver.maps.Service.Status.OK)
          return alert("Something wrong!");

        // 제대로 된 query가 들어가 response가 return되는 경우
        var result = response.v2, // 검색 결과의 컨테이너
          items = result.addresses; // 검색 결과의 배열

        let x = parseFloat(items[0].x); // 경도
        let y = parseFloat(items[0].y); // 위도

        setLat(y); //위도 상태 변경
        setLng(x); //경도 상태 변경
        setZoom(15); //주소 검색 후 화면 zoom되도록 zoom level 15로 변경
        setRoadAddress(items[0].roadAddress); //도로명 주소
      }
    );
  }

  //jsx
  return ( 
    <>
      <div className="map-loader">
        <div className="map" style={{ width: "100%", height: "100%" }}>
        //NaverMapAPI 컴포넌트에 zoom 레벨, 경도, 위도, 를 전달한다.
          <NaverMapAPI
            zoom={zoom}
            Latitude={lat}
            Longtitude={lng}
            roadAddress={roadAddress}
          />
        </div>
        <div className="search-container">
          <form>
            <input
              className="findAddress"
              placeholder="주소로 검색"
              onChange={handleChange}
            />
            //검색 button에 click event 발생 시 searchAddressToCoordinate함수 호출
            <button
              className="submitAddress-button"
              type="submit"
              onClick={() => searchAddressToCoordinate(address.address)}
            >
              🔎
            </button>
          </form>
        </div>
      </div>
    </>
  );
};
export default Home;

 

728x90