페어 활동 기록_Day16_한빈_현정 - boostcampwm-2022/web33-Mildo GitHub Wiki
- (지난주) 핀이 포커싱 될 경우 커지는 기능 완성(#29)
- (지난주) 핀 클릭시 상세 모달창 출력(#34)
- 배열의 index보다 _id를 저장하는 것이 좋을 것 같음
- 핀 관련 기능을 완성한다.
- 핀마다 이벤트 추가
- 핀 클릭 시 핀이 화면 가운데로 이동
- 핀 클릭 시 핀 크기가 커짐
- InfoDetailModal 열고 닫는 기능 구현, 전역 변수로 관리
- 상세 정보 모달에 실제 데이터베이스에서 가져온 데이터 출력
- 상세 정보 모달에 넘치는 글자 애니메이션 적용
- 다른 핀을 클릭했을 때 이미 클릭되었던 핀 클릭 해제
- 핀을 클릭하면 해당 핀과 관련된 정보를 담은 모달창을 출력
-
기존 로직에는
Map
컴포넌트에 네이버 지도를 렌더하는 로직과 마커를 그리는 로직이 같이 있어 한 컴포넌트가 많은 일을 함 -
Map
컴포넌트에서는 마커를 찍을 때 필요한 정보들(위도/경도, 인구 밀도 정보 등)만 가져오고 그 데이터를Marker
컴포넌트에 내려주기→
Map
컴포넌트는 네이버 지도를 그리고 데이터를 불러오는 로직만 가지고 있고,Marker
컴포넌트는 마커를 그려주기만 하면 된다. -
Marker
와 관련된 비즈니스 로직과 렌더링 코드를 분리
-
이전에는
naver.maps.Marker
들의 배열이 있었으나, 리팩토링 이후 응답으로 받은 데이터의 배열(areas
)을map
을 이용하여Marker
컴포넌트를 생성함→
naver.maps.Marker
배열이 없음 -
선택된 marker의 인덱스를 저장할 수 없으므로 선택된 marker가 무엇인지 찾으려면
areas
배열을 순회하며 찾아야 함→ 너무 비효율적
-
상위 컴포넌트인
Map
컴포넌트에서onClickMarker
함수를Marker
컴포넌트의 props로 내려줌-
Marker
컴포넌트에서는 현재 marker가 클릭되면 marker의 크기를 크게 함 -
onClickMarker
함수- 이전에 선택된 marker(
prevPlace.current.marker
)의 크기를 작게 함 - 지금 클릭한 marker를
prevPlace.current.marker
에 저장
- 이전에 선택된 marker(
→ 이전에 선택된 마커를 저장해놓았기 때문에 순회를 하지 않아도 크기 조정 가능
-
MainPage
ㄴ InfoDetailModal
ㄴ Map
ㄴ Marker
-
Marker
컴포넌트에서 이벤트가 발생하면InfoDetailModal
이 보여져야 함 -
InfoDetailModal
의 state인isInfoDetailModalOpen
를 접근해야 함, 관련 함수 접근 방법은- props 드릴링
- 전역 변수로 관리
- 모달창이 열리는 것은 맵을 클릭하거나, 마커를 클릭했을 때 등 관련된 컴포넌트가 많을 것으로 보여 jotai를 사용하여 전역으로 관리
- 핀의 클릭 이벤트를 부모(Map)의 이벤트 위임으로 설정하면 문제점이 있음
- 모바일과 데스크탑에서 동시에 같은 이벤트를 걸어줄 수 없음
- click 이벤트를 사용하면 데스크탑에서만 작동함
- touchend 이벤트를 사용하면 모바일에서 자기 마음대로 선택이됨
- 네이버 마커 이벤트로 click 이벤트를 걸어줌
- 모바일과 데스크탑에서 동시에 같은 이벤트를 걸어줄 수 있음
- 모바일에서 자기 마음대로 선택되는 일이 없음
- 함수의 인자에 타입을 설정하고, 함수 자체는 () → void로 설정하면 됨
-
Map.tsx의 prevPlace를 useState로 선언하면 setState가 안먹힘
- 그래서 대안으로 useRef로 설정했더니 멀쩡하게 값이 잘 변경됨
const Map: React.FC<MapComponentProps> = ({ latitude, longitude }) => { const mapRef = useRef(null); const [naverMap, setNaverMap] = useState<naver.maps.Map | null>(null); const [areas, setAreas] = useState<SortAllAreasTypes[]>([]); const prevPlace = useRef<PrevPlaceTypes | null>(null); }
-
optional
const onClickMarker = (marker: object, populationLevel: string) => { ... const { _nmarker_id: newMarkerId }:{ _nmarker_id?: string } = marker; ... }
-
naver.maps.Marker, MarkerObjectTypes
interface MarkerObjectTypes { _nmarker_id?: string; } const onClickMarker = (marker: naver.maps.Marker, populationLevel: string) => { ... const { _nmarker_id: newMarkerId }: MarkerObjectTypes = marker; prevPlace.current.marker.setIcon({ content: `<div>${createPinSvg(prevPlace.current.populationLevel)}</div>`, size: new naver.maps.Size(35, 50), anchor: new naver.maps.Point(17.5, 50), origin: new naver.maps.Point(0, 0) }); ... }
-
MarkerObjectTypes
커스텀 타입을 만들고marker
타입을naver.maps.Marker
로 바꾸어줌 - (
prevPlace.current.marker
의 타입도naver.maps.Marker
임) - 문제점
-
naver.maps.Marker
에는MarkerObjectTypes
가 존재하지 않아_nmarker_id
를 불러오지 못함 -
marker
를MarkerObjectTypes
로 하면MarkerObjectTypes
에는setIcon
이 존재하지 않아 해당 메소드 사용 불가
-
-
-
MarkerObjectTypes에 setIcon 추가
interface MarkerObjectTypes { _nmarker_id?: string; setIcon: ( icon: | string | naver.maps.ImageIcon | naver.maps.SymbolIcon | naver.maps.HtmlIcon ) => void; } const onClickMarker = (marker: MarkerObjectTypes, populationLevel: string) => { ... const { _nmarker_id: newMarkerId } = marker; prevPlace.current.marker.setIcon({ content: `<div>${createPinSvg(prevPlace.current.populationLevel)}</div>`, size: new naver.maps.Size(35, 50), anchor: new naver.maps.Point(17.5, 50), origin: new naver.maps.Point(0, 0) }); ... }
-
setIcon
을 포함한MarkerObjectTypes
인터페이스 생성 - (
prevPlace.current.marker
의 타입도MarkerObjectTypes
임)
-
- 핀 이외의 지도 영역을 클릭했을 때 핀 포커싱 해제