구현한 내용
- 게시글 수정시 장소와 메모의 CRUD 반영하기
- 장소 정보 지도에 실시간 반영하기
- 코스-지도 연동하기
- 리덕스 데이터 초기화
글쓰기페이지에서는 CRUD와 지도에 관한 정보를 리덕스에서 처리한 후 리덕스 데이터를 파이어베이스에 저장했고, 상세페이지에서는 파이어베이스에 있는 정보를 그대로 불러왔다.
게시글 수정페이지의 경우 파이어베이스에 있는 정보를 불러와서 다시 CRUD를 실행하는 작업이 필요했으므로 글쓰기페이지와 상세페이지에서 사용한 방법을 모두 적용해서 아래와 같이 구현했다.
- 파이어베이스에서 불러온 정보를 리덕스에 저장하기
- 리덕스 저장된 데이터로 CRUD 수행하기
- 최종적으로 수정한 리덕스 데이터를 파이어베이스에 반영하기
EidtCourseMap.tsx
lists.map((item: any) => {
if (item.id === filteredId) {
bounds = Object.setPrototypeOf(
item.bounds,
kakao.maps.LatLngBounds.prototype
);
}
});
게시글 작성시 JSON.stringify
를 사용해서 코스 데이터를 저장하고 있기 때문에 이 데이터를 불러올 때는 JSON.parse
를 거치고, 그 후 코스 데이터에 포함된 지도 범위 데이터를 불러오기 위해 setPrototypeOf
를 거쳐야 했다. (카카오맵 bounds 정보 firebase에 추가하기)
이 과정에서 Uncaught TypeError: #<Object> is not extensible at Function.setPrototypeOf (<anonymous>)
라는 이슈가 발생했다.
리덕스에 저장된 프로토타입은 변경이 불가능하기 때문에 발생한 버그였다.
📌 React - TypeScript 실행오류 Cannot add property, object is not extensible
📌 TypeError : "x"속성을 정의 할 수 없습니다 : "obj"는 확장 할 수 없습니다
리덕스에 저장한 데이터 대신 파이어베이스에 있는 기존의 데이터를 가져와서 프로토타입 변환하였다.
현재는 프로토타입 버그 때문에 파이어베이스에서만 데이터를 불러오고 있으므로 새로운 코스 추가시 지도에 반영이 되지 않는다. 새로운 코스의 정보도 필요하므로 실시간 정보가 반영되는 리덕스 데이터를 사용한다.
EditCourseMap.tsx
let fbBounds: any;
let reduxBounds: any;
const fbLists = JSON.parse(initLists.courseList);
const reduxLists = useSelector(
(state: any) => state.temporarySlice.courseList
);
fbLists.map((item: any) => {
if (item.id === filteredId) {
fbBounds = Object.setPrototypeOf(
item.bounds,
kakao.maps.LatLngBounds.prototype
);
}
});
reduxLists.map((item: any) => {
if (item.id === filteredId) {
reduxBounds = item.bounds;
}
});
useEffect(() => {
const ps = new kakao.maps.services.Places();
ps.keywordSearch(searchKeyword, (data, status, pagination) => {
if (status === kakao.maps.services.Status.OK) {
const kakaoBounds = new kakao.maps.LatLngBounds();
let markers = [];
for (var i = 0; i < data.length; i++) {
(중략)
kakaoBounds.extend(new kakao.maps.LatLng(data[i].y, data[i].x));
}
// @ts-ignore
map.panTo(kakaoBounds);
reduxBounds = kakaoBounds;
}
});
}, [searchKeyword]);
useEffect(() => {
if (map !== undefined) {
if (fbBounds) {
// @ts-ignore
map.panTo(fbBounds);
}
if (reduxBounds) {
// @ts-ignore
map.panTo(reduxBounds);
}
}
}, [filteredId]);
1. 지도 범위(bounds
)값을 파이어베이스(=기존에 작성한) 데이터와 리덕스(=새로 추가한) 데이터로 분리
리덕스 데이터의 경우, 카카오맵 API에서 받아온 정보를 즉시 저장하고 있으므로 프로토타입을 변환할 필요가 없다.
2. 검색 실행시 지도 범위 재설정 map.panTo(kakaoBounds);
카드 클릭시 지도 범위를 해당 코스의 정보로 재설정하기 위해 검색 결과를 반영한 지도 범위값(kakaobounds
)을 reduxBounds
에 할당한다.
3. 카드 클릭시 useEffect
로 지도 범위 재설정
카드 클릭시 반 화면 반환
a.e is not a function.
점선 위는 파이어베이스에서 불러온 데이터의 bounds
값이고, 아래는 새로 추가한 장소의 bounds
값이다.
기존 카드 클릭시 fbBounds
만 받아와야 하는데 fbbounds
와 reduxBounds
를 모두 받아오고 있으므로 useEffect
에서 map.panTo
가 동시에 실행돼 해당 에러가 발생했던 것이다.
reduxLists.map((item: any) => {
if (item.id === filteredId) {
reduxBounds = item.bounds;
}
});
fbbounds
와 reduxBounds
가 동시에 저장되는 원인은 위 코드에 있다. reduxBounds
를 충족하는 조건은 클릭한 카드의 id와 reduxLists
에 포함된 요소의 id가 같을 때이다.
EditCourse.tsx
// 수정 전 내용 불러오기
useEffect(() => {
(중략)
dispatch(replaceAllData(JSON.parse(course?.courseList)));
}, []);
수정페이지 접속시 파이어베이스의 데이터를 리덕스에 복사하고 있으므로 기존에 작성한 카드를 클릭해도 reduxBounds
가 같이 반환될 수밖에 없는 것이다.
if (fbBounds === undefined) {
reduxLists.map((item: any) => {
if (item.id === filteredId) {
reduxBounds = item.bounds;
}
});
}
useEffect(() => {
if (map !== undefined) {
if (fbBounds !== undefined) {
// @ts-ignore
map.panTo(fbBounds);
}
if (reduxBounds !== undefined) {
// @ts-ignore
map.panTo(reduxBounds);
}
}
}, [filteredId]);
리덕스 데이터 클릭시에는 fbBounds
값이 undefined
였던 점을 이용해서 예외처리를 해주었다.
글쓰기페이지와 수정페이지 모두 같은 리덕스 모듈을 사용하고 있기 때문에 글쓰기를 중단하고 수정페이지에 접속하거나, 수정을 중단하고 글쓰기페이지 접속시 기존의 작성/수정 내용이 남아있는 버그를 발견했다.
그래서 글쓰기 페이지 접속, 게시글 등록, 글쓰기 취소, 게시글 수정, 게시글 수정 취소 실행시 dispatch(replaceAllData([]))
로 리덕스 데이터를 초기화 했다.