자취방 리뷰 페이지는 자취생들이 자신들이 살던 자취방에 대한 후기를 쓸 수 있는 페이지다. 우리 프로젝트에서 가장 독특한 기능이고, 시중에도 자취방을 구하는 앱은 있지만 후기를 달 수 있는 서비스는 없어서 만들어 봤다. 앞서 블로그에서도 봤겠지만 프로젝트 기간이 갑자기 늘어나는 바람에 추가로 넣을 기능을 생각하다 넣은거라서 모든 기능을 약1주일만에 만들었다. 그래도 내가 제안한 아이디어를 제작한 거라서 가장 재밌게 만들었던 기억이 있다.
🗺️ 자취방 리뷰 페이지
⚒️ 내가 한 기능
1. 초기위치는 현위치로 고정
2. 지도 클릭시 클릭한 곳의 주소 추출
3. 리뷰 달고 볼 수 있게 구현
4. 지도가 움직임에 따라 지도에 포함된 리뷰들만 보이게 구현
5. 주소 검색 후 해당 지역으로 이동
6. 현위치 버튼 구현
7. 리뷰가 겹처진 부분은 클러스터러를 사용해서 보여줌
지도는 카카오 맵API를 가져왔고, 주소 검색은 다음주소 검색 API를 가져왔다. 현위치는 geolocation을 사용해 구현했다.
확인 모달 창은 부트스트랩을 사용했다.
🤔 컴포넌트 구조
총 4개의 컴포넌트로 만들었다.
지도 부분은 리뷰를 달 수 있는 지도와 리뷰를 볼 수 있는 지도를 구분해서 만들었다. 또한 자취방 후기를 남길 수 있는 란과 작성한 리뷰들을 볼 수 있는 란을 만들어 총 4개의 컴포넌트로 구성했다.
지도를 사용한 프로젝트는 이전에도 한번 해본 경험이 있어서 이전과는 달리 새롭게 써본 기술 위주로 블로깅 할 예정이다.
1. 주소 변경하기
클릭한 곳으로 마커를 이동하고 주소를 바꿔주는 함수다.
// 주소-좌표 변환 객체를 생성
var geocoder = new window.kakao.maps.services.Geocoder();
geocoder.coord2Address(
mouseEvent.latLng.getLng(),
mouseEvent.latLng.getLat(),
(result: any, status: boolean) => {
if (
status === window.kakao.maps.services.Status.OK
) {
let addr = !!result[0].road_address
? result[0].road_address.address_name
: result[0].address.address_name;
setMylat(mouseEvent.latLng.getLat());
setMylng(mouseEvent.latLng.getLng());
// 클릭한 위치 주소를 가저온다.
setAddress(addr);
// 기존 마커와 인포윈도우를 지우고 새로운 마커를 생성
if (marker) {
marker.setMap(null);
}
// 마커를 클릭한 위치에 표시합니다
marker.setPosition(mouseEvent.latLng);
marker.setMap(map);
}
},
);
클릭한 곳이든 주소 검색을 통해 이동한 곳이든 우측 컴포넌트 주소란에 실시간으로 바뀌도록 만들었다. 전역상태로 state값을 만들어 관리를 해줬다. 마우스로 클릭한 곳은 주소-좌표 변환 객체를 생성해서 주소로 바꾼 후 주소 상태 state값을 바꿔준다. 그리고 이전에 마크된 마커가 있다면 지워주는 조건문을 만들어준다.
2. 지도에 보이는 리뷰들만 나타나게 하기
사실 이부분이 가장 공들였던 부분이다. 지도에 보이는 리뷰만 나타나게 하는 건 생각보다 쉬웠다. 하지만 마커를 클릭했을 때 고유의 정보가 나와야 했고 그 리뷰의 높이에 따라 아래 스크롤의 높이가 달라져야 했다.
지도에 보이는 리뷰만 나타나게 하는 함수는 아래와 같다.
useEffect(() => {
if (map) {
kakao.maps.event.addListener(map, 'bounds_changed', function () {
// 지도 영역정보를 얻어옵니다
let bounds = map.getBounds();
// 영역정보의 남서쪽 정보를 얻어옵니다
let sw = bounds.getSouthWest();
// 영역정보의 북동쪽 정보를 얻어옵니다
let ne = bounds.getNorthEast();
// 지도영역 마커만 filter
if (markers) {
const selectedMarker = markers.filter((item: any) => {
// 현재 지도 영역의 남서쪽, 북동쪽 좌표
let lb = new kakao.maps.LatLngBounds(sw, ne);
let l1 = new kakao.maps.LatLng(
item.latitude,
item.longitude,
);
// true -> 출력O
// false -> 출력X
return lb.contain(l1);
});
setVisibleMarker(selectedMarker);
}
});
}
}, [map]);
간단하게 요약하면 지도가 움직일 때마다 지도의 북동쪽 남서쪽 좌표를 기준으로 그 안에 내가 저장한 좌표만 filter해서 추출하는 작업이다.
마커를 클릭했을 때 나오는 고유의 정보는 데이터를 저장할 때 주소,위도,경도,날짜를 저장한다. 데이터를 받아올 때는 위도,경도,내용이 맞는 데이터를 추출한 후 그 마커에 주소, 날짜를 주입시켰다.
// 데이터를 보낼 때
axios
.post(
`${process.env.REACT_APP_API_KEY}/roomRivewWrite`,
{
address: address,
content: content,
latitude: mylat,
longitude: mylng,
},
{
headers: {
Authorization: `Bearer ${token}`,
},
},
)
// 데이터를 받아 올 때
const markerList = markers.map((markerData: any) => {
const marker = new kakao.maps.Marker({
position: new kakao.maps.LatLng(
markerData.latitude,
markerData.longitude,
),
map: kakaoMap,
title: markerData.content,
image: markerImage, // 마커 이미지
});
marker.address = markerData.address;
marker.createdAt = markerData.createdAt;
})
클릭시 방 리뷰의 길이에 따라 "내가 본 자취방 리뷰" Div박스의 높이가 달라진다. 이것은 핫딜 페이지를 했을 때와 같이 useEffect의 deps에 마커를 클릭했는지 안했는지에 대한 state값을 넣어주고 그 값이 변할 때마다 Div박스의 offsetHeight값을 구해준다.
// useEffect를 사용하여 _ClickedReview의 높이를 계산하고 업데이트합니다.
useEffect(() => {
if (clickedReviewRef.current) {
setClickedReviewHeight(clickedReviewRef.current.offsetHeight);
}
}, [clickedContent]); // markerOnOff가 변경될 때마다 다시 계산
3. 리뷰가 겹처진 부분은 클러스터러를 사용해서 보여줌
생각보다 클러스터러도 쉽게 구현할 수 있었다.
DB에 저장된 마커들을 모두 불러온 후에 아래의 함수 안에 넣으면 끝!
// 클러스터러를 만들고 지도에 추가
const clusterer = new kakao.maps.MarkerClusterer({
map: kakaoMap,
averageCenter: true,
minLevel: 1,
});
// 클러스터 추가
clusterer.addMarkers(markerList);
역시 kakaoApi는 정리가 잘되있고 참고할 만한 레퍼런스가 많아서 그런지 하고 싶은 기능이 있으면 왠만한건 다 있었다.
'프로젝트' 카테고리의 다른 글
[개인 프로젝트] - 포트폴리오 웹 사이트만들기 (1) | 2024.02.09 |
---|---|
[리팩토링] - JinCha 프로젝트 뜯어 고치기 (2) | 2024.01.28 |
[포스코x코딩온] 웹개발자 풀스택 과정 4차 팀프로젝트 - 핫딜 페이지(2) (0) | 2023.12.12 |
[포스코x코딩온] 웹개발자 풀스택 과정 4차 팀프로젝트 - 핫딜 페이지(1) (0) | 2023.12.12 |
[포스코x코딩온] 웹개발자 풀스택 과정 4차 팀프로젝트 - Zustand (0) | 2023.12.11 |