본문 바로가기
Develop/ReactNative

RN 카카오 맵 + 공공데이터 API 사용하기

by ys2ys2 2024. 11. 15.

화면 위에 카카오 맵 API 사용해서 webview 형식으로 불러오는 거 까지 성공한 상태에서 추가 작업하기!

 

상단에 버튼을 두고 버튼 누를 시

javascript로 공공데이터포털에서 제공하는 전기차 충전소 제공 API를 사용해보려고 했다.

 


 

☑️ 충전소 찾기 버튼 + 드롭다운 리스트

 

일단 상단에 주변 충전소 찾기 라는 버튼을 하나 두고

버튼을 클릭 시 드롭다운 리스트가 나오게 했고

사용자가 시/도 선택시 시/군을 선택 할 수 있는 리스트가 활성화되게 했다.

각각 시/도와 시/군에는 value값을 둬서 전기차 충전소 API를 호출할 때 사용할 수 있게 했다.

충청남도에 해당하는 value 44를 선택하게 되면 cityDistricts에서 값을 가져온다.

여기서 다음 드롭다운이 활성화되면서 시/군이 사용자한테 보여지고,

천안을 선택하면 value: 44130이 api호출시에 사용되게 된다.

const cityDistricts = {
	...
     "44": [
	        { value: "44250", text: "계룡시" },
	        { value: "44150", text: "공주시" },
	        { value: "44710", text: "금산군" },
	        { value: "44230", text: "논산시" },
	        { value: "44270", text: "당진시" },
	        { value: "44180", text: "보령시" },
	        { value: "44760", text: "부여군" },
	        { value: "44210", text: "서산시" },
	        { value: "44770", text: "서천군" },
	        { value: "44200", text: "아산시" },
	        { value: "44810", text: "예산군" },
	        { value: "44130", text: "천안시" },
	        { value: "44790", text: "청양군" },
	        { value: "44825", text: "태안군" },
	        { value: "44800", text: "홍성군" }
	    ],
        ...
       }
<View style={styles.buttonContainer}>
<TouchableOpacity style={styles.button} onPress={toggleDropdown}>
  <Text style={styles.buttonText}>주변 충전소 찾기</Text>
</TouchableOpacity>
</View>

{/* 현재 위치로 이동하는 아이콘 버튼 */}
<TouchableOpacity style={styles.locationButton} onPress={handleMoveToCurrentLocation}>
<Icon name="my-location" size={24} color="black" />
</TouchableOpacity>

{dropdownVisible && (
<View style={styles.dropdownContainer}>
  <Text style={styles.dropdownTitle}>시/도 선택</Text>
  <Picker
    selectedValue={selectedCity}
    style={styles.picker}
    onValueChange={(value) => {
      setSelectedCity(value);
      setSelectedDistrict(''); // 시/도 변경 시 시/군 초기화
    }}
  >
    <Picker.Item label="시/도" value="" />
    <Picker.Item label="서울특별시" value="11" />
    <Picker.Item label="부산광역시" value="26" />
    <Picker.Item label="대구광역시" value="27" />
    <Picker.Item label="인천광역시" value="28" />
    <Picker.Item label="광주광역시" value="29" />
    <Picker.Item label="대전광역시" value="30" />
    <Picker.Item label="울산광역시" value="31" />
    <Picker.Item label="세종특별자치시" value="36" />
    <Picker.Item label="경기도" value="41" />
    <Picker.Item label="충청북도" value="43" />
    <Picker.Item label="충청남도" value="44" />
    <Picker.Item label="전북특별자치도" value="52" />
    <Picker.Item label="전라남도" value="46" />
    <Picker.Item label="경상북도" value="47" />
    <Picker.Item label="경상남도" value="48" />
    <Picker.Item label="제주특별자치도" value="50" />
    <Picker.Item label="강원특별자치도" value="51" />
  </Picker>

  <Text style={styles.dropdownTitle}>시/군 선택</Text>
  <Picker
    selectedValue={selectedDistrict}
    style={styles.picker}
    onValueChange={(value) => setSelectedDistrict(value)}
    enabled={selectedCity !== ''}
  >
    <Picker.Item label="시/군" value="" />
    {getDistrictsByCity(selectedCity).map((district) => (
      <Picker.Item key={district.value} label={district.text} value={district.value} />
    ))}
  </Picker>

  <TouchableOpacity style={styles.searchButton} onPress={handleSearch}>
    <Text style={styles.searchButtonText}>검색</Text>
  </TouchableOpacity>
</View>

 

주변 충전소 찾기 버튼, 드롭다운 리스트

 

이렇게 해서 검색 버튼을 누르면 해당하는 선택된 시/군과 시/도에 해당하는 value값을 api호출시에 전달해서

해당하는 지역의 전기차 충전소의 정보를 가지고 오는게 목적!

선택된 시/도, 시/군

 

그러고 기존에 웹에서 사용하던 api호출 부분을 가져왔다.

테스트 겸 충전소 이름, 주소, 위도와 경도를 가져왔다.

위도 경도로는 마커를 표시하는데 사용했고 마커를 클릭 시 충전소 이름,주소가 뜨게 했다.

api 호출 시

zcode에 해당하는 값은 selectedCity에서 가져오게 했고,

zscode에 해당하는 값은 selectedDistrict에서 가져오게 했다.

그러면 최종적으로 시/도 → 시/군에 해당하는 API가 호출되는게 목적!

테스트니까 numOfRows=100, pageNo=1!

const apiKey = "공공데이터 API 키";
const apiUrl = `http://apis.data.go.kr/B552584/EvCharger/getChargerInfo?serviceKey=${encodeURIComponent(apiKey)}&numOfRows=100&pageNo=1&dataType=JSON&zcode=${selectedCity}&zscode=${selectedDistrict}`;


    try {
      const response = await fetch(apiUrl);
      if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
      
      const data = await response.json();
      
      if (data.items && data.items.item) {
        const chargerData = data.items.item.map((charger) => ({
          name: charger.statNm,
          address: charger.addr,
          lat: parseFloat(charger.lat),
          lng: parseFloat(charger.lng),
        }));
        setChargers(chargerData);
        addMarkersToMap(chargerData);
      } else {
        console.log("충전소 데이터를 찾을 수 없습니다.");
      }
    } catch (error) {
      console.error("Error fetching data:", error);
    }
  };

 

 

상단에 충전소 정보의 배열들을 저장할 useState배열도 추가하고

const [chargers, setChargers] = useState([]);

 

마커를 추가할 addMarkersToMap도 추가했다.

또한 추가된 마커를 클릭할 때 charger값에 저장해둔 name, address도 표시하게 하고 테스트!

콘솔에도 값 찍어보기!

const addMarkersToMap = (chargers) => {
if (webViewRef.current) {
  // 모든 마커의 위치를 포함할 수 있도록 bounds 객체 생성
  const boundsJS = chargers.map((charger) => `
    new kakao.maps.LatLng(${charger.lat}, ${charger.lng})
  `).join(',');

  const markersJS = chargers.map((charger) => `
    (function() {
      const position = new kakao.maps.LatLng(${charger.lat}, ${charger.lng});
      const marker = new kakao.maps.Marker({
        position: position,
        map: map,
        title: '${charger.name}'
      });
      kakao.maps.event.addListener(marker, 'click', function () {
        const infoContent = '<div><h3>${charger.name}</h3><p>${charger.address}</p></div>';
        const infoWindow = new kakao.maps.InfoWindow({ content: infoContent });
        infoWindow.open(map, marker);
      });
    })();
  `).join('\n');

  console.log("Markers JS:", markersJS);

  webViewRef.current.injectJavaScript(`
        (function() {
            const bounds = new kakao.maps.LatLngBounds();
            [${boundsJS}].forEach((position) => bounds.extend(position));

            // 마커 추가
            ${markersJS}

            map.setBounds(bounds);
        })();
  `);
}
};

 

테스트 결과

 

console

 

잘 불러와지는거 같다.


 

 

지도에 마커가 찍히면서 마커들이 다 나오는지, 마커를 눌렀을 때 해당 충전소의 값들이 나오는지 테스트!

 

충전소 마커, 충전소 정보 가져오기

 

잘 불러와진다!

 

이제 테스트로 찍은 name, adress, lat, lng 말고도 추가 값들을 가져와서 마커 클릭 시 보여지게 하고

//값 더 추가하기
name: charger.statNm,
address: charger.addr,
lat: parseFloat(charger.lat),
lng: parseFloat(charger.lng),
...

 

충전소 팝업 부분 css 후

길 찾기 기능을 넣으면 될 것 같다.

길 찾기 기능은 카카오 모빌리티 API 사용하면 될 것 같다! 웹에서 해봤으니까!

 


 

 

☑️ 내 위치 버튼 + 마커 추가

 

 

추가적으로 좌측 하단에 내 위치 아이콘을 넣어서

내 위치로 이동하게 하면서 마커가 찍히게 추가!

react-native-vector-icons 라이브러리를 사용했다.

import Icon from 'react-native-vector-icons/MaterialIcons';



const handleMoveToCurrentLocation = () => {
  if (webViewRef.current) {
    const jsCode = `
      (function() {
        const position = new kakao.maps.LatLng(${location.latitude}, ${location.longitude});
        map.setCenter(position);
        map.setLevel(4);
        
        const marker = new kakao.maps.Marker({
          position: position,
          map: map,
        });
        
      })();
    `;
    webViewRef.current.injectJavaScript(jsCode);
  }
};

{/* 현재 위치로 이동하는 아이콘 버튼 */}
<TouchableOpacity style={styles.locationButton} onPress={handleMoveToCurrentLocation}>
	<Icon name="my-location" size={24} color="black" />
</TouchableOpacity>

 

현재 위치 + 마커

 

추가적으로 해야 할 것들

1. 100개로 가져오고 있는 부분을 페이지네이션이나 다른 방법으로 계속 새로 가져올 수 있게 추가

2. 길 찾기 기능 추가

3. 충전소 결과에 해당하는 마커 클릭 시 충전소 정보 팝업 제공

4. 충전소 정보 팝업에 길 찾기 버튼 추가 및 길 찾기 버튼 클릭 시 도착지로 위도,경도 넘기기

5. 현재 위치에 해당하는 위도,경도를 길 찾기 기능의 출발지로 넘기기

6. 길 찾기 버튼 클릭 시 나오는 네비게이션 정보 가공(1000m 이상 단위 1km로, 좌,우회전 등등 스타일링)

 

7. 같은 방식으로 주차장, 기름 페이지 추가

8. 최초 앱 접속시 메인페이지

 

일단 이정도만 하면.. 진행하는 프로젝트랑 비슷하게 구현할 수 있을 거 같다!

 


 

웹으로 한 작업들을 다시 앱으로 변환하고 있어서 어떤 걸 해야할지는 바로바로 정할 수 있지만

RN언어랑 학원에서 배우고 있는 JSP나 JPA랑은 달라서 많이 어렵다!

1차 프로젝트를 리액트로 했지만 그땐 아무것도 모르고 들이박았던 수준이라 새로 배우는 마음으로 하는중,,

 

3차 프로젝트 끝낼 때 까지 웹과 앱 두개를 다 할 수 있을지 모르겠지만

 

일단 해봐야지!!!