const renderListingMarkers = useCallback(
async (m: naver.maps.Map) => {
if (listOpen) return;
const response = await searchListing(m, getFilterFromSearchParams());
setTotalListingCount(response?.total_result_count || 0);
const markers: ListingMarkers = {};
response?.results?.forEach((item) => {
const key = `lat:${item.lat}lng:${item.long}`;
markers[key] = item;
});
setListingMarkers(markers);
},
[listOpen],
);
Object.entries 사용 (객체 -> 배열 메서드 사용)
{Object.entries(listingMarkers).map(([key, marker]) => {
return (
<CustomOverlay
key={key}
position={{
lat: marker.lat,
lng: marker.long,
}}
>
{marker.bubjungdong_name ? (
<NamedListingMarker
onClick={() => onClickListingMarker(marker)}
color="primary"
name={marker.bubjungdong_name || ''}
count={marker.count}
/>
) : (
<ListingMarker
onClick={() => onClickListingMarker(marker)}
count={marker.count}
/>
)}
</CustomOverlay>
);
})}
class OverlayView extends naver.maps.OverlayView {
private _element: HTMLElement | undefined;
private _position: naver.maps.LatLng;
constructor(element: HTMLElement, position: naver.maps.LatLng) {
super();
this._element = element;
this._position = position;
}
setPosition(position: naver.maps.LatLng) {
this._position = position;
this.draw();
}
getPosition() {
return this._position;
}
onAdd() {
if (!this._element) return;
const { overlayLayer } = this.getPanes();
overlayLayer.appendChild(this._element);
}
onRemove() {
if (!this._element) return;
this._element.remove();
}
draw() {
if (!this.getMap() || !this._element) return;
const projection = this.getProjection();
const position = this.getPosition();
const pixelPosition = projection.fromCoordToOffset(position);
const offsetX = this._element.clientWidth / 2;
const offsetY = this._element.clientHeight / 2;
this._element.style.position = 'absolute';
this._element.style.left = `${pixelPosition.x - offsetX}px`;
this._element.style.top = `${pixelPosition.y - offsetY}px`;
}
}
클래스로 관리
export function CustomOverlay({
id,
className,
position,
children,
}: CustomOverlayProps) {
const map = useContext(NaverMapContext);
const container = useRef(document.createElement('div'));
const overlayPosition = useMemo(() => {
if (!naver.maps) {
return null;
}
return new naver.maps.LatLng(position.lat, position.lng);
}, [position.lat, position.lng]);
const overlay = useMemo(() => {
if (overlayPosition) {
return new OverlayView(container.current, overlayPosition);
}
return null;
}, [overlayPosition]);
useEffect(() => {
if (!map) return () => {};
overlay?.setMap(map);
return () => {
overlay?.setMap(null);
};
}, [map, overlay]);
useEffect(() => {
if (overlayPosition) {
overlay?.setPosition(overlayPosition);
}
}, [overlay, overlayPosition]);
useEffect(() => {
if (id) container.current.id = id;
}, [id]);
useEffect(() => {
if (className) container.current.className = className;
}, [className]);
return ReactDOM.createPortal(children, container.current);
}
createPortal
재조정