👩🏻💻 Today Learn
🤦🏻♀️ 고민한 부분
KakaoMapMarker
컴포넌트는 카카오맵으로 희망하는 장소를 선택하면 해당 위치의 위도, 경도, 주소정보를 가지고 올 수 있다.
// KakaoMapMarker
'use client';
import style from './kakaoMapMarker.module.scss';
import Script from 'next/script';
import { Map, MapMarker, MapTypeControl, ZoomControl } from 'react-kakao-maps-sdk';
import { useState, useEffect } from 'react';
import { useAddress, usePosition } from '@/hooks/useKakaoMapMarker';
const KAKAO_SDK_URL = `//dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_APP_KEY}&libraries=services&autoload=false`;
const KakaoMapMarker = () => {
const [currentLocation, setCurrentLocation] = useState<{ latitude: number; longitude: number }>({
latitude: 33.450701,
longitude: 126.570667
});
const [position, setPosition] = useState<{ lat: number; lng: number }>();
const [address, setAddress] = useState<string>('');
const mapClickHandler = (_t: any, mouseEvent: any) => {
const lat = mouseEvent.latLng.getLat();
const lng = mouseEvent.latLng.getLng();
setPosition({ lat, lng });
getAddress(lat, lng);
};
// 위도, 경도로 주소 정보 가져오기
const getAddress = (lat: number, lng: number) => {
const geocoder = new kakao.maps.services.Geocoder();
const coord = new kakao.maps.LatLng(lat, lng);
const callback = (result: any, status: any) => {
if (status === kakao.maps.services.Status.OK) {
setAddress(result[0].address.address_name);
console.log('결과', result);
}
};
geocoder.coord2Address(coord.getLng(), coord.getLat(), callback);
};
// 현재위치를 시작점으로 만들기
useEffect(() => {
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition(
(position) => {
setCurrentLocation({
latitude: position.coords.latitude,
longitude: position.coords.longitude
});
},
() => {
console.log('위치 받기에 실패하였습니다');
setCurrentLocation({ latitude: 33.450701, longitude: 126.570667 });
}
);
}
}, []);
return (
// ...
);
};
export default KakaoMapMarker;
여기서 position
과 address
값을 원래는 state
로 관리하였었는데 이 컴포넌트를 상품을 등록하는 페이지에서 불러와서 사용하면서부터 고민이 시작되었다.
위도, 경도, 주소값을 전달해주는 방법에 대해 고민을 하다가 전역으로 관리해보라는 튜터님의 조언을 듣고 Zustand
를 처음 사용하게 되었다.
Redux
보다 훨씬 간편한게 장점이라고 했기 때문에 유튜브와 블로그와 문서를보며...
딱 이렇게 사용하였다!
// import { useCallback, useState } from 'react';
import { create } from 'zustand';
export type Position = {
position: { lat: number; lng: number };
setPosition: (position: { lat: number; lng: number }) => void;
};
export type Address = {
address: string;
setAddress: (address: string) => void;
};
const usePosition = create<Position>((set) => ({
position: { lat: 0, lng: 0 },
setPosition: (position) => set(() => ({ position }))
}));
const useAddress = create<Address>((set) => ({
address: '',
setAddress: (address) => set(() => ({ address }))
}));
export { usePosition, useAddress };
type을 지정해 주지 않으면 사용하는 부분에서 이러한 오류를 마주할 수 있다.
그리고 업데이트를 해주고 필요한 부분에서 가져올 수 있다.
// KakaoMapMarker
const setPosition = usePosition((state) => state.setPosition);
const setAddress = useAddress((state) => state.setAddress);
// CreateForm
const position = usePosition((state) => state.position);
const address = useAddress((state) => state.address);
//CreateForm
const [inputForm, setInputForm] = useState<TablesInsert<'used_item'>>({
title: '',
address: address,
content: '',
latitude: position.lat,
longitude: position.lng,
main_category_id: 0,
sub_category_id: 0,
photo_url: [],
place_name: '',
price: 0,
sold_out: false,
user_id: user?.id!
});
console에 초기에는 {lat:0, lng:0}
주소는 빈값이었다가 위치를 클릭하면 해당 정보가 찍히는 것을 볼 수 있다.
그런데 찍은 정보값이 등록하기를 클릭하면 데이터에 빈값으로 들어가는 것이 문제였다.
inputForm에 값을 담아주는 로직이었는데 초기값에만 넣어주고 setInputForm
을 해주지 않은 것이다...
위치와 장소값이 초기 렌더링 시점에 초기값으로 설정되어있는 상태에서 위치를 변경하면 자동으로 업데이트 되길 바란것이다 😏
useEffect(() => {
setInputForm((prev) => ({
...prev,
address: address,
latitude: position.lat,
longitude: position.lng
}));
}, [address, position]);
usePosition
과 useAddress
에서 상태를 가져오는 것은 비동기적으로 발생할 수 있어 최신상태로 업데이트가 되지 않는다.
그래서 useEffect
를 사용하여 address
와 position
이 바뀔때마다 inputForm을 펼쳐서 그 안에 그 값들을 넣어주는 코드를 추가해주었더니
계속 빈값이었던 데이터가 들어온 것을 확인할 수 있다!!
✍🏻 회고
Zustand
는 처음 사용해보았는데 Redux
에 비해 정말 간단해서 신기하면서도 프로젝트가 커지면 괜찮을까? 하는 생각도 들었다. 그래도 이 기회에 겉핥기 식으로 사용해보아서 좋았다.
해결에 어려움을 겪었던 데이터 전달하는 부분은 분명히 어려운게 아닌건 느껴졌는데 명확히 콕찝어 찾아내지 못하고 헤맸던게 아쉬웠다 ㅠㅠ