From d8529ae542368160211e2b89ebfa1d3a005b0cf0 Mon Sep 17 00:00:00 2001 From: jong yoon Date: Mon, 9 Dec 2019 00:13:11 +0900 Subject: [PATCH 1/8] =?UTF-8?q?FETURE:=20=EC=A7=80=EC=97=AD=EA=B5=AC=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=EC=8B=9C=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 지도에서 원하는 지역구 클릭시 지도에 표현 및 상태 저장 --- .../src/components/match/MatchMap/index.jsx | 218 ++++++++++++------ 1 file changed, 153 insertions(+), 65 deletions(-) diff --git a/client/src/components/match/MatchMap/index.jsx b/client/src/components/match/MatchMap/index.jsx index 448c8209..a2e64189 100644 --- a/client/src/components/match/MatchMap/index.jsx +++ b/client/src/components/match/MatchMap/index.jsx @@ -4,13 +4,75 @@ import axios from 'axios'; import MDSpinner from 'react-md-spinner'; import './index.scss'; -const SEOUL = { - KOREAN: '서울', - DISTRICT_CNT: '25', +let districtInfo = { + 종로구: { + namePosition: { x: 126.9831947, y: 37.5829365 }, + isSelected: false, + }, + 중구: { namePosition: { x: 126.9955543, y: 37.5595345 }, isSelected: false }, + 용산구: { isSelected: false }, + 성동구: { isSelected: false }, + 광진구: { namePosition: { x: 127.083445, y: 37.5448365 }, isSelected: false }, + 동대문구: { + namePosition: { x: 127.0525459, y: 37.5807599 }, + isSelected: false, + }, + 중랑구: { isSelected: false }, + 성북구: { + namePosition: { x: 127.0209602, y: 37.5998031 }, + isSelected: false, + }, + 강북구: { namePosition: { x: 127.0113472, y: 37.6357 }, isSelected: false }, + 도봉구: { + namePosition: { x: 127.0340065, y: 37.6628831 }, + isSelected: false, + }, + 노원구: { + namePosition: { x: 127.0752052, y: 37.6509238 }, + isSelected: false, + }, + 은평구: { namePosition: { x: 126.9275764, y: 37.616666 }, isSelected: false }, + 서대문구: { + namePosition: { x: 126.9337562, y: 37.5742296 }, + isSelected: false, + }, + 마포구: { + namePosition: { x: 126.9069771, y: 37.5568129 }, + isSelected: false, + }, + 양천구: { + namePosition: { x: 126.8554787, y: 37.5183333 }, + isSelected: false, + }, + 강서구: { + namePosition: { x: 126.8211464, y: 37.5624572 }, + isSelected: false, + }, + 구로구: { + namePosition: { x: 126.8424324, y: 37.4925533 }, + isSelected: false, + }, + 금천구: { isSelected: false }, + 영등포구: { isSelected: false }, + 동작구: { + namePosition: { x: 126.9509224, y: 37.5023592 }, + isSelected: false, + }, + 관악구: { isSelected: false }, + 서초구: { + namePosition: { x: 127.0106605, y: 37.4794768 }, + isSelected: false, + }, + 강남구: { + namePosition: { x: 127.0552925, y: 37.4952773 }, + isSelected: false, + }, + 송파구: { isSelected: false }, + 강동구: { isSelected: false }, }; const NAVER_MAP_API_REQUEST_URL = `https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=${process.env.REACT_APP_NCP_CLIENT_ID}`; -const SEOUL_DISTRICT_REQUEST_URL = `/req/data?request=GetFeature&key=${process.env.REACT_APP_MAP_DISTRICT_KEY}&size=${SEOUL.DISTRICT_CNT}&data=LT_C_ADSIGG_INFO&attrfilter=full_nm:like:${SEOUL.KOREAN}&domain=${process.env.REACT_APP_DOMAIN}`; +const SEOUL_DISTRICT_REQUEST_URL = `/req/data?request=GetFeature&key=${process.env.REACT_APP_MAP_DISTRICT_KEY}&size=25&data=LT_C_ADSIGG_INFO&attrfilter=full_nm:like:서울&domain=${process.env.REACT_APP_DOMAIN}`; const markerElement = { mapTitle: @@ -23,26 +85,6 @@ const markerElement = { }, }; -const districtNamePostion = { - 강서구: { x: 126.8211464, y: 37.5624572 }, - 양천구: { x: 126.8554787, y: 37.5183333 }, - 동작구: { x: 126.9509224, y: 37.5023592 }, - 서초구: { x: 127.0106605, y: 37.4794768 }, - 강남구: { x: 127.0552925, y: 37.4952773 }, - 종로구: { x: 126.9831947, y: 37.5829365 }, - 성북구: { x: 127.0209602, y: 37.5998031 }, - 강북구: { x: 127.0113472, y: 37.6357 }, - 도봉구: { x: 127.0340065, y: 37.6628831 }, - 노원구: { x: 127.0752052, y: 37.6509238 }, - 동대문구: { x: 127.0525459, y: 37.5807599 }, - 서대문구: { x: 126.9337562, y: 37.5742296 }, - 마포구: { x: 126.9069771, y: 37.5568129 }, - 구로구: { x: 126.8424324, y: 37.4925533 }, - 광진구: { x: 127.083445, y: 37.5448365 }, - 은평구: { x: 126.9275764, y: 37.616666 }, - 중구: { x: 126.9955543, y: 37.5595345 }, -}; - const MatchMap = () => { const [naverMapData, setNaverMapData] = useState(); const [seoulDistrictData, setSeoulDistrictData] = useState(); @@ -92,26 +134,39 @@ const NaverMap = (props) => { normal: mapData.NaverStyleMapTypeOption.getBlankMap(), }), }; - const naverMapStyleConfig = { - fillColor: '#71ACAD', - fillOpacity: 0.6, - strokeColor: '#71ACAD', - strokeOpacity: 1, - strokeWeight: 2, - strokeStyle: 'solid', - clickable: true, - zIndex: 4, - }; - const selectedDistrictOption = () => { - const styleOption = { ...naverMapStyleConfig }; - styleOption.fillColor = '#71ACAD'; - styleOption.fillOpacity = 1; - styleOption.strokeColor = '#71ACAD'; - styleOption.strokeOpacity = 1; - styleOption.strokeStyle = 'solid'; - styleOption.strokeWeight = 1; - styleOption.zIndex = 5; - return styleOption; + + const setDistrictOption = (action) => { + const defaultOption = { + strokeOpacity: 1, + strokeWeight: 2, + }; + /* eslint indent: ["error", 2, { "SwitchCase": 1 }] */ + switch (action) { + case 'mouseover': + return { + ...defaultOption, + fillColor: '#71ACAD', + fillOpacity: 1, + strokeColor: '#71ACAD', + zIndex: 5, + }; + case 'click': + return { + ...defaultOption, + fillColor: '#373d75', + fillOpacity: 0.6, + strokeColor: '#373d75', + zIndex: 6, + }; + default: + return { + ...defaultOption, + fillColor: '#71ACAD', + fillOpacity: 0.6, + strokeColor: '#71ACAD', + zIndex: 4, + }; + } }; const addEvent = (isGlobal, target, action, handler) => { @@ -127,12 +182,12 @@ const NaverMap = (props) => { }; const getDistrictCenter = (district, name) => { - if (!districtNamePostion[name]) { + if (districtInfo[name].namePosition === undefined) { return district.getBounds().getCenter(); } return new mapData.LatLng( - districtNamePostion[name].y, - districtNamePostion[name].x + districtInfo[name].namePosition.y, + districtInfo[name].namePosition.x ); }; @@ -147,34 +202,54 @@ const NaverMap = (props) => { }, map: naverMap, }); - const handleMarkerEvent = (option) => { - district.setStyle(option); - }; - addEvent( - true, - districtMarker, - 'mouseover', - handleMarkerEvent.bind(null, selectedDistrictOption()) - ); - addEvent( - true, - districtMarker, - 'mouseout', - handleMarkerEvent.bind(null, naverMapStyleConfig) - ); + addEvent(true, districtMarker, 'mouseover', () => { + const curDistrict = district.property_sig_kor_nm; + if (districtInfo[curDistrict].isSelected) { + return; + } + district.setStyle(setDistrictOption('mouseover')); + }); + addEvent(true, districtMarker, 'mouseout', () => { + const curDistrict = district.property_sig_kor_nm; + if (districtInfo[curDistrict].isSelected) { + return; + } + district.setStyle(setDistrictOption()); + }); + addEvent(true, districtMarker, 'click', () => { + const selectedDistrict = district.property_sig_kor_nm; + const preDistrictInfo = { ...districtInfo }; + preDistrictInfo[selectedDistrict].isSelected = !preDistrictInfo[ + selectedDistrict + ].isSelected; + districtInfo = preDistrictInfo; + const curAction = preDistrictInfo[selectedDistrict].isSelected + ? 'click' + : ''; + district.setStyle(setDistrictOption(curAction)); + console.log(districtInfo); + }); }; const handleDistrictMouseoverEvent = (e) => { if (districtMarker) { districtMarker.setMap(null); } - const selecteDistrictOption = selectedDistrictOption(); + const curDistrict = e.feature.property_sig_kor_nm; + if (districtInfo[curDistrict].isSelected) { + return; + } + const selecteDistrictOption = setDistrictOption('mouseover'); e.feature.setStyle(selecteDistrictOption); createDistrictNameMarker(e.feature, selecteDistrictOption); }; const handleDistrictMouseoutEvent = (e) => { - e.feature.setStyle(naverMapStyleConfig); + const curDistrict = e.feature.property_sig_kor_nm; + if (districtInfo[curDistrict].isSelected) { + return; + } + e.feature.setStyle(setDistrictOption()); }; const handleDistrictMousemoveEvent = () => { @@ -202,9 +277,22 @@ const NaverMap = (props) => { districtData.forEach((district) => { naverMap.data.addGeoJson(district); }); - naverMap.data.setStyle(naverMapStyleConfig); + naverMap.data.setStyle(setDistrictOption()); addEvent(false, naverMap.data, 'mouseover', handleDistrictMouseoverEvent); addEvent(false, naverMap.data, 'mouseout', handleDistrictMouseoutEvent); + addEvent(false, naverMap.data, 'click', (e) => { + const selectedDistrict = e.feature.property_sig_kor_nm; + const preDistrictInfo = { ...districtInfo }; + preDistrictInfo[selectedDistrict].isSelected = !preDistrictInfo[ + selectedDistrict + ].isSelected; + districtInfo = { ...preDistrictInfo }; + const curAction = preDistrictInfo[selectedDistrict].isSelected + ? 'click' + : ''; + e.feature.setStyle(setDistrictOption(curAction)); + console.log(districtInfo); + }); addEvent(true, naverMap, 'mousemove', handleDistrictMousemoveEvent); } /* eslint react-hooks/exhaustive-deps: 0 */ From 86c868b2f6c684daa2f8251bc9dae435cc42278d Mon Sep 17 00:00:00 2001 From: jong yoon Date: Mon, 9 Dec 2019 04:07:02 +0900 Subject: [PATCH 2/8] =?UTF-8?q?FEATURE:=20=EC=A7=80=EC=97=AD=EA=B5=AC=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=EC=8B=9C=20=EB=A7=88=EC=BB=A4=20=EA=B3=A0?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 선택한 지역구의 마커는 사라지지 않도록 고정 이외에 리펙토링 진행 --- .../src/components/match/MatchMap/index.jsx | 257 +++++++++++------- 1 file changed, 157 insertions(+), 100 deletions(-) diff --git a/client/src/components/match/MatchMap/index.jsx b/client/src/components/match/MatchMap/index.jsx index a2e64189..016e5ed9 100644 --- a/client/src/components/match/MatchMap/index.jsx +++ b/client/src/components/match/MatchMap/index.jsx @@ -6,69 +6,99 @@ import './index.scss'; let districtInfo = { 종로구: { - namePosition: { x: 126.9831947, y: 37.5829365 }, + namePosition: { x: 126.9672221, y: 37.5883778 }, + isSelected: false, + }, + 중구: { namePosition: { x: 126.9805817, y: 37.5666103 }, isSelected: false }, + 용산구: { + namePosition: { x: 126.9605354, y: 37.5383031 }, + isSelected: false, + }, + 성동구: { + namePosition: { x: 127.0216469, y: 37.5562685 }, + isSelected: false, + }, + 광진구: { + namePosition: { x: 127.0690254, y: 37.5508249 }, isSelected: false, }, - 중구: { namePosition: { x: 126.9955543, y: 37.5595345 }, isSelected: false }, - 용산구: { isSelected: false }, - 성동구: { isSelected: false }, - 광진구: { namePosition: { x: 127.083445, y: 37.5448365 }, isSelected: false }, 동대문구: { - namePosition: { x: 127.0525459, y: 37.5807599 }, + namePosition: { x: 127.0320798, y: 37.5889219 }, + isSelected: false, + }, + 중랑구: { + namePosition: { x: 127.0758919, y: 37.5992591 }, isSelected: false, }, - 중랑구: { isSelected: false }, 성북구: { - namePosition: { x: 127.0209602, y: 37.5998031 }, + namePosition: { x: 126.9983009, y: 37.608507 }, + isSelected: false, + }, + 강북구: { + namePosition: { x: 126.9948677, y: 37.6427686 }, isSelected: false, }, - 강북구: { namePosition: { x: 127.0113472, y: 37.6357 }, isSelected: false }, 도봉구: { - namePosition: { x: 127.0340065, y: 37.6628831 }, + namePosition: { x: 127.0161403, y: 37.6683185 }, isSelected: false, }, 노원구: { - namePosition: { x: 127.0752052, y: 37.6509238 }, + namePosition: { x: 127.0587257, y: 37.6509238 }, + isSelected: false, + }, + 은평구: { + namePosition: { x: 126.909037, y: 37.6231925 }, isSelected: false, }, - 은평구: { namePosition: { x: 126.9275764, y: 37.616666 }, isSelected: false }, 서대문구: { - namePosition: { x: 126.9337562, y: 37.5742296 }, + namePosition: { x: 126.9122767, y: 37.5807599 }, isSelected: false, }, 마포구: { - namePosition: { x: 126.9069771, y: 37.5568129 }, + namePosition: { x: 126.8843178, y: 37.5638889 }, isSelected: false, }, 양천구: { - namePosition: { x: 126.8554787, y: 37.5183333 }, + namePosition: { x: 126.8348793, y: 37.5281454 }, isSelected: false, }, 강서구: { - namePosition: { x: 126.8211464, y: 37.5624572 }, + namePosition: { x: 126.8061737, y: 37.5687873 }, isSelected: false, }, 구로구: { - namePosition: { x: 126.8424324, y: 37.4925533 }, + namePosition: { x: 126.8259529, y: 37.4990907 }, + isSelected: false, + }, + 금천구: { namePosition: { x: 126.8816311, y: 37.466943 }, isSelected: false }, + 영등포구: { + namePosition: { x: 126.8911842, y: 37.5290465 }, isSelected: false, }, - 금천구: { isSelected: false }, - 영등포구: { isSelected: false }, 동작구: { - namePosition: { x: 126.9509224, y: 37.5023592 }, + namePosition: { x: 126.9296364, y: 37.5099851 }, + isSelected: false, + }, + 관악구: { + namePosition: { x: 126.9268898, y: 37.4723928 }, isSelected: false, }, - 관악구: { isSelected: false }, 서초구: { - namePosition: { x: 127.0106605, y: 37.4794768 }, + namePosition: { x: 126.9886879, y: 37.4887396 }, isSelected: false, }, 강남구: { - namePosition: { x: 127.0552925, y: 37.4952773 }, + namePosition: { x: 127.0456795, y: 37.4969117 }, + isSelected: false, + }, + 송파구: { + namePosition: { x: 127.0985512, y: 37.5088957 }, + isSelected: false, + }, + 강동구: { + namePosition: { x: 127.1280769, y: 37.5589902 }, isSelected: false, }, - 송파구: { isSelected: false }, - 강동구: { isSelected: false }, }; const NAVER_MAP_API_REQUEST_URL = `https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=${process.env.REACT_APP_NCP_CLIENT_ID}`; @@ -78,8 +108,9 @@ const markerElement = { mapTitle: '
서울 지역구 풋살 매칭 현황 지도
', districtName: (name) => { + const width = (name.length + 2) * 10; return ` -
+
${name}
`; }, @@ -122,6 +153,17 @@ const NaverMap = (props) => { const { mapData, districtData } = props; const [naverMap, setNaverMap] = useState(undefined); + const createMapTitleMarker = () => { + return new mapData.Marker({ + position: mapData.Position.TOP_LEFT, + clickable: false, + icon: { + content: markerElement.mapTitle, + }, + map: naverMap, + }); + }; + const mapInitOptions = { zoom: 11, draggable: false, @@ -181,75 +223,113 @@ const NaverMap = (props) => { } }; - const getDistrictCenter = (district, name) => { - if (districtInfo[name].namePosition === undefined) { - return district.getBounds().getCenter(); + // 현재 마우스 이벤트에 따라 나오는 마커 + let districtMarker; + // 선택한 지역구의 마커들 + let selectedDistrictMarker = {}; + + const showSelectedDistrictMarker = () => { + Object.values(selectedDistrictMarker).forEach((marker) => { + marker.setMap(naverMap); + }); + }; + + const hideAllDistrictMarker = () => { + Object.values(selectedDistrictMarker).forEach((marker) => { + marker.setMap(null); + }); + }; + + // 마커와 지역구에 등록할 공통 이벤트 + const mouseoverEvent = (target) => { + const curDistrictName = target.property_sig_kor_nm; + if (districtInfo[curDistrictName].isSelected) { + return; + } + target.setStyle(setDistrictOption('mouseover')); + }; + + const mouseoutEvent = (target) => { + const curDistrictName = target.property_sig_kor_nm; + showSelectedDistrictMarker(); + if (districtInfo[curDistrictName].isSelected) { + return; } - return new mapData.LatLng( - districtInfo[name].namePosition.y, - districtInfo[name].namePosition.x - ); + target.setStyle(setDistrictOption()); }; - let districtMarker; + const clickEvent = (target) => { + const curDistrictName = target.property_sig_kor_nm; + hideAllDistrictMarker(); + const preDistrictInfo = { ...districtInfo }; + const isSelected = !preDistrictInfo[curDistrictName].isSelected; + preDistrictInfo[curDistrictName].isSelected = isSelected; + districtInfo = preDistrictInfo; + const curAction = isSelected ? 'click' : ''; + target.setStyle(setDistrictOption(curAction)); + if (isSelected) { + if (!selectedDistrictMarker[curDistrictName]) { + selectedDistrictMarker[curDistrictName] = districtMarker; + } + showSelectedDistrictMarker(); + return; + } + if (selectedDistrictMarker[curDistrictName]) { + const newMarkers = {}; + Object.entries(selectedDistrictMarker).forEach(([markerName, marker]) => { + if (markerName !== curDistrictName) { + newMarkers[markerName] = marker; + } + }); + selectedDistrictMarker = { ...newMarkers }; + } + showSelectedDistrictMarker(); + }; + + // 지역구 이름 마커 생성 함수 const createDistrictNameMarker = (district) => { - const name = district.property_sig_kor_nm; + const curDistrictName = district.property_sig_kor_nm; districtMarker = new mapData.Marker({ - position: getDistrictCenter(district, name), + position: new mapData.LatLng( + districtInfo[curDistrictName].namePosition.y, + districtInfo[curDistrictName].namePosition.x + ), clickable: true, icon: { - content: markerElement.districtName(name), + content: markerElement.districtName(curDistrictName), }, map: naverMap, }); - addEvent(true, districtMarker, 'mouseover', () => { - const curDistrict = district.property_sig_kor_nm; - if (districtInfo[curDistrict].isSelected) { - return; - } - district.setStyle(setDistrictOption('mouseover')); - }); - addEvent(true, districtMarker, 'mouseout', () => { - const curDistrict = district.property_sig_kor_nm; - if (districtInfo[curDistrict].isSelected) { - return; - } - district.setStyle(setDistrictOption()); - }); - addEvent(true, districtMarker, 'click', () => { - const selectedDistrict = district.property_sig_kor_nm; - const preDistrictInfo = { ...districtInfo }; - preDistrictInfo[selectedDistrict].isSelected = !preDistrictInfo[ - selectedDistrict - ].isSelected; - districtInfo = preDistrictInfo; - const curAction = preDistrictInfo[selectedDistrict].isSelected - ? 'click' - : ''; - district.setStyle(setDistrictOption(curAction)); - console.log(districtInfo); - }); + addEvent( + true, + districtMarker, + 'mouseover', + mouseoverEvent.bind(null, district) + ); + addEvent( + true, + districtMarker, + 'mouseout', + mouseoutEvent.bind(null, district) + ); + addEvent(true, districtMarker, 'click', clickEvent.bind(null, district)); }; + // 지역구에 등록할 이벤트 const handleDistrictMouseoverEvent = (e) => { if (districtMarker) { districtMarker.setMap(null); } - const curDistrict = e.feature.property_sig_kor_nm; - if (districtInfo[curDistrict].isSelected) { - return; - } - const selecteDistrictOption = setDistrictOption('mouseover'); - e.feature.setStyle(selecteDistrictOption); - createDistrictNameMarker(e.feature, selecteDistrictOption); + mouseoverEvent(e.feature); + createDistrictNameMarker(e.feature); }; const handleDistrictMouseoutEvent = (e) => { - const curDistrict = e.feature.property_sig_kor_nm; - if (districtInfo[curDistrict].isSelected) { - return; - } - e.feature.setStyle(setDistrictOption()); + mouseoutEvent(e.feature); + }; + + const handleDistrictClickEvent = (e) => { + clickEvent(e.feature); }; const handleDistrictMousemoveEvent = () => { @@ -258,17 +338,6 @@ const NaverMap = (props) => { } }; - const createMapTitleMarker = () => { - return new mapData.Marker({ - position: mapData.Position.TOP_LEFT, - clickable: false, - icon: { - content: markerElement.mapTitle, - }, - map: naverMap, - }); - }; - useEffect(() => { if (naverMap === undefined) { setNaverMap(new mapData.Map('map', mapInitOptions)); @@ -280,19 +349,7 @@ const NaverMap = (props) => { naverMap.data.setStyle(setDistrictOption()); addEvent(false, naverMap.data, 'mouseover', handleDistrictMouseoverEvent); addEvent(false, naverMap.data, 'mouseout', handleDistrictMouseoutEvent); - addEvent(false, naverMap.data, 'click', (e) => { - const selectedDistrict = e.feature.property_sig_kor_nm; - const preDistrictInfo = { ...districtInfo }; - preDistrictInfo[selectedDistrict].isSelected = !preDistrictInfo[ - selectedDistrict - ].isSelected; - districtInfo = { ...preDistrictInfo }; - const curAction = preDistrictInfo[selectedDistrict].isSelected - ? 'click' - : ''; - e.feature.setStyle(setDistrictOption(curAction)); - console.log(districtInfo); - }); + addEvent(false, naverMap.data, 'click', handleDistrictClickEvent); addEvent(true, naverMap, 'mousemove', handleDistrictMousemoveEvent); } /* eslint react-hooks/exhaustive-deps: 0 */ From c140db5210e93cab0428cbbe70ce05ffc5a1dfe4 Mon Sep 17 00:00:00 2001 From: jong yoon Date: Mon, 9 Dec 2019 15:31:44 +0900 Subject: [PATCH 3/8] =?UTF-8?q?CHORE:=20=EC=A7=80=EB=8F=84=20=EB=84=88?= =?UTF-8?q?=EB=B9=84=20=ED=81=AC=EA=B8=B0=20=EA=B3=A0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 좌우로 브라우저를 좁혔을때, 지도도 같이 줄어들어 짤리는 현상 방지하기 위해 크기 고정 --- client/public/index.html | 1 + client/src/components/match/MatchRegistModal/index.scss | 5 ++++- client/src/index.scss | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/client/public/index.html b/client/public/index.html index 16fde6bb..bbfd4cad 100644 --- a/client/public/index.html +++ b/client/public/index.html @@ -4,6 +4,7 @@ + Date: Mon, 9 Dec 2019 15:33:14 +0900 Subject: [PATCH 4/8] =?UTF-8?q?FIX:=20=EC=A7=80=EC=97=AD=EA=B5=AC=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EB=AA=A8=EB=93=88=ED=99=94=20=EB=B0=8F=20?= =?UTF-8?q?=EB=A6=AC=ED=8E=99=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 지역구 정보를 util/district.js 로 분할하여 사용 따라서, 해당 관련 정보를 사용하는 함수들의 코드 수정 코드를 수정하면서 리펙토링 진행 --- .../src/components/match/MatchMap/index.jsx | 160 +++++------------- 1 file changed, 38 insertions(+), 122 deletions(-) diff --git a/client/src/components/match/MatchMap/index.jsx b/client/src/components/match/MatchMap/index.jsx index 016e5ed9..138ef290 100644 --- a/client/src/components/match/MatchMap/index.jsx +++ b/client/src/components/match/MatchMap/index.jsx @@ -2,105 +2,9 @@ import React, { useState, useEffect } from 'react'; import loadJs from 'load-js'; import axios from 'axios'; import MDSpinner from 'react-md-spinner'; +import { changeDistrictInfo, findDistrictToName } from '../../../util'; import './index.scss'; -let districtInfo = { - 종로구: { - namePosition: { x: 126.9672221, y: 37.5883778 }, - isSelected: false, - }, - 중구: { namePosition: { x: 126.9805817, y: 37.5666103 }, isSelected: false }, - 용산구: { - namePosition: { x: 126.9605354, y: 37.5383031 }, - isSelected: false, - }, - 성동구: { - namePosition: { x: 127.0216469, y: 37.5562685 }, - isSelected: false, - }, - 광진구: { - namePosition: { x: 127.0690254, y: 37.5508249 }, - isSelected: false, - }, - 동대문구: { - namePosition: { x: 127.0320798, y: 37.5889219 }, - isSelected: false, - }, - 중랑구: { - namePosition: { x: 127.0758919, y: 37.5992591 }, - isSelected: false, - }, - 성북구: { - namePosition: { x: 126.9983009, y: 37.608507 }, - isSelected: false, - }, - 강북구: { - namePosition: { x: 126.9948677, y: 37.6427686 }, - isSelected: false, - }, - 도봉구: { - namePosition: { x: 127.0161403, y: 37.6683185 }, - isSelected: false, - }, - 노원구: { - namePosition: { x: 127.0587257, y: 37.6509238 }, - isSelected: false, - }, - 은평구: { - namePosition: { x: 126.909037, y: 37.6231925 }, - isSelected: false, - }, - 서대문구: { - namePosition: { x: 126.9122767, y: 37.5807599 }, - isSelected: false, - }, - 마포구: { - namePosition: { x: 126.8843178, y: 37.5638889 }, - isSelected: false, - }, - 양천구: { - namePosition: { x: 126.8348793, y: 37.5281454 }, - isSelected: false, - }, - 강서구: { - namePosition: { x: 126.8061737, y: 37.5687873 }, - isSelected: false, - }, - 구로구: { - namePosition: { x: 126.8259529, y: 37.4990907 }, - isSelected: false, - }, - 금천구: { namePosition: { x: 126.8816311, y: 37.466943 }, isSelected: false }, - 영등포구: { - namePosition: { x: 126.8911842, y: 37.5290465 }, - isSelected: false, - }, - 동작구: { - namePosition: { x: 126.9296364, y: 37.5099851 }, - isSelected: false, - }, - 관악구: { - namePosition: { x: 126.9268898, y: 37.4723928 }, - isSelected: false, - }, - 서초구: { - namePosition: { x: 126.9886879, y: 37.4887396 }, - isSelected: false, - }, - 강남구: { - namePosition: { x: 127.0456795, y: 37.4969117 }, - isSelected: false, - }, - 송파구: { - namePosition: { x: 127.0985512, y: 37.5088957 }, - isSelected: false, - }, - 강동구: { - namePosition: { x: 127.1280769, y: 37.5589902 }, - isSelected: false, - }, -}; - const NAVER_MAP_API_REQUEST_URL = `https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=${process.env.REACT_APP_NCP_CLIENT_ID}`; const SEOUL_DISTRICT_REQUEST_URL = `/req/data?request=GetFeature&key=${process.env.REACT_APP_MAP_DISTRICT_KEY}&size=25&data=LT_C_ADSIGG_INFO&attrfilter=full_nm:like:서울&domain=${process.env.REACT_APP_DOMAIN}`; @@ -243,7 +147,7 @@ const NaverMap = (props) => { // 마커와 지역구에 등록할 공통 이벤트 const mouseoverEvent = (target) => { const curDistrictName = target.property_sig_kor_nm; - if (districtInfo[curDistrictName].isSelected) { + if (findDistrictToName(curDistrictName).isSelected) { return; } target.setStyle(setDistrictOption('mouseover')); @@ -252,47 +156,59 @@ const NaverMap = (props) => { const mouseoutEvent = (target) => { const curDistrictName = target.property_sig_kor_nm; showSelectedDistrictMarker(); - if (districtInfo[curDistrictName].isSelected) { + if (findDistrictToName(curDistrictName).isSelected) { return; } target.setStyle(setDistrictOption()); }; - const clickEvent = (target) => { - const curDistrictName = target.property_sig_kor_nm; - hideAllDistrictMarker(); - const preDistrictInfo = { ...districtInfo }; - const isSelected = !preDistrictInfo[curDistrictName].isSelected; - preDistrictInfo[curDistrictName].isSelected = isSelected; - districtInfo = preDistrictInfo; - const curAction = isSelected ? 'click' : ''; - target.setStyle(setDistrictOption(curAction)); - if (isSelected) { - if (!selectedDistrictMarker[curDistrictName]) { - selectedDistrictMarker[curDistrictName] = districtMarker; - } - showSelectedDistrictMarker(); + const deleteMarkerInSelectedMarkers = (curDistrictName) => { + if (!selectedDistrictMarker[curDistrictName]) { return; } + const newMarkers = {}; + Object.entries(selectedDistrictMarker).forEach(([name, marker]) => { + if (name !== curDistrictName) { + newMarkers[name] = marker; + } + }); + selectedDistrictMarker = { ...newMarkers }; + }; + + const insertMarkerInSelectedMarkers = (curDistrictName) => { if (selectedDistrictMarker[curDistrictName]) { - const newMarkers = {}; - Object.entries(selectedDistrictMarker).forEach(([markerName, marker]) => { - if (markerName !== curDistrictName) { - newMarkers[markerName] = marker; - } - }); - selectedDistrictMarker = { ...newMarkers }; + return; } + const newMarkers = { ...selectedDistrictMarker }; + newMarkers[curDistrictName] = districtMarker; + selectedDistrictMarker = { ...newMarkers }; + }; + + const clickEvent = (target) => { + hideAllDistrictMarker(); + const curDistrictName = target.property_sig_kor_nm; + const preTargetInfo = { ...findDistrictToName(curDistrictName) }; + preTargetInfo.isSelected = !preTargetInfo.isSelected; + changeDistrictInfo(preTargetInfo); + + const curAction = preTargetInfo.isSelected ? 'click' : ''; + target.setStyle(setDistrictOption(curAction)); + + const processMarkerAction = preTargetInfo.isSelected + ? insertMarkerInSelectedMarkers + : deleteMarkerInSelectedMarkers; + processMarkerAction(curDistrictName); showSelectedDistrictMarker(); }; // 지역구 이름 마커 생성 함수 const createDistrictNameMarker = (district) => { const curDistrictName = district.property_sig_kor_nm; + const districtInfo = findDistrictToName(curDistrictName); districtMarker = new mapData.Marker({ position: new mapData.LatLng( - districtInfo[curDistrictName].namePosition.y, - districtInfo[curDistrictName].namePosition.x + districtInfo.namePosition.y, + districtInfo.namePosition.x ), clickable: true, icon: { From 62e5fd4255c69eb60e9cbfdbd5eccac1949a829b Mon Sep 17 00:00:00 2001 From: jong yoon Date: Mon, 9 Dec 2019 15:35:16 +0900 Subject: [PATCH 5/8] =?UTF-8?q?FEATURE:=20=EC=A7=80=EC=97=AD=EA=B5=AC=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EB=AA=A8=EB=93=88=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 공통으로 사용되는 지역구 정보를 모듈화 --- client/src/util/district.js | 166 ++++++++++++++++++++++++++++++++++++ client/src/util/index.js | 44 +++------- 2 files changed, 179 insertions(+), 31 deletions(-) create mode 100644 client/src/util/district.js diff --git a/client/src/util/district.js b/client/src/util/district.js new file mode 100644 index 00000000..302edc2e --- /dev/null +++ b/client/src/util/district.js @@ -0,0 +1,166 @@ +let DISTRICT = { + CNO: { + KOR_NAME: '종로구', + namePosition: { x: 126.9672221, y: 37.5883778 }, + isSelected: false, + }, + CGS: { + KOR_NAME: '중구', + namePosition: { x: 126.9805817, y: 37.5666103 }, + isSelected: false, + }, + YSN: { + KOR_NAME: '용산구', + namePosition: { x: 126.9605354, y: 37.5383031 }, + isSelected: false, + }, + SDG: { + KOR_NAME: '성동구', + namePosition: { x: 127.0216469, y: 37.5562685 }, + isSelected: false, + }, + KJI: { + KOR_NAME: '광진구', + namePosition: { x: 127.0690254, y: 37.5508249 }, + isSelected: false, + }, + TDM: { + KOR_NAME: '동대문구', + namePosition: { x: 127.0320798, y: 37.5889219 }, + isSelected: false, + }, + CNG: { + KOR_NAME: '중랑구', + namePosition: { x: 127.0758919, y: 37.5992591 }, + isSelected: false, + }, + SBK: { + KOR_NAME: '성북구', + namePosition: { x: 126.9983009, y: 37.608507 }, + isSelected: false, + }, + KBK: { + KOR_NAME: '강북구', + namePosition: { x: 126.9948677, y: 37.6427686 }, + isSelected: false, + }, + TBG: { + KOR_NAME: '도봉구', + namePosition: { x: 127.0161403, y: 37.6683185 }, + isSelected: false, + }, + NWN: { + KOR_NAME: '노원구', + namePosition: { x: 127.0587257, y: 37.6509238 }, + isSelected: false, + }, + UPG: { + KOR_NAME: '은평구', + namePosition: { x: 126.909037, y: 37.6231925 }, + isSelected: false, + }, + SDM: { + KOR_NAME: '서대문구', + namePosition: { x: 126.9122767, y: 37.5807599 }, + isSelected: false, + }, + MPO: { + KOR_NAME: '마포구', + namePosition: { x: 126.8843178, y: 37.5638889 }, + isSelected: false, + }, + YGC: { + KOR_NAME: '양천구', + namePosition: { x: 126.8348793, y: 37.5281454 }, + isSelected: false, + }, + KSS: { + KOR_NAME: '강서구', + namePosition: { x: 126.8061737, y: 37.5687873 }, + isSelected: false, + }, + KRO: { + KOR_NAME: '구로구', + namePosition: { x: 126.8259529, y: 37.4990907 }, + isSelected: false, + }, + KCN: { + KOR_NAME: '금천구', + namePosition: { x: 126.8816311, y: 37.466943 }, + isSelected: false, + }, + YDP: { + KOR_NAME: '영등포구', + namePosition: { x: 126.8911842, y: 37.5290465 }, + isSelected: false, + }, + TJK: { + KOR_NAME: '동작구', + namePosition: { x: 126.9296364, y: 37.5099851 }, + isSelected: false, + }, + KNK: { + KOR_NAME: '관악구', + namePosition: { x: 126.9268898, y: 37.4723928 }, + isSelected: false, + }, + SCO: { + KOR_NAME: '서초구', + namePosition: { x: 126.9886879, y: 37.4887396 }, + isSelected: false, + }, + KNM: { + KOR_NAME: '강남구', + namePosition: { x: 127.0456795, y: 37.4969117 }, + isSelected: false, + }, + SPA: { + KOR_NAME: '송파구', + namePosition: { x: 127.0985512, y: 37.5088957 }, + isSelected: false, + }, + KDG: { + KOR_NAME: '강동구', + namePosition: { x: 127.1280769, y: 37.5589902 }, + isSelected: false, + }, +}; + +const setDistrict = (nextInfo) => { + DISTRICT = { ...nextInfo }; +}; + +const getDistrict = () => { + return DISTRICT; +}; + +const convertDistrictCode = (code) => { + return DISTRICT[code].KOR_NAME; +}; + +const convertDistrictName = (name) => { + return Object.keys(DISTRICT).filter( + (code) => DISTRICT[code].KOR_NAME === name + )[0]; +}; + +const findDistrictToName = (name) => { + return Object.values(DISTRICT).filter( + (district) => district.KOR_NAME === name + )[0]; +}; + +const changeDistrictInfo = (changedInfo) => { + const code = convertDistrictName(changedInfo.KOR_NAME); + const nextInfos = getDistrict(); + nextInfos[code] = { ...changedInfo }; + setDistrict(nextInfos); +}; + +export { + convertDistrictCode, + setDistrict, + getDistrict, + findDistrictToName, + changeDistrictInfo, +}; diff --git a/client/src/util/index.js b/client/src/util/index.js index 4d17cb58..14f345de 100644 --- a/client/src/util/index.js +++ b/client/src/util/index.js @@ -1,33 +1,15 @@ -const codeMap = { - CNO: '종로구', - CGS: '중구', - YSN: '용산구', - SDG: '성동구', - KJI: '광진구', - TDM: '동대문구', - CNG: '중랑구', - SBK: '성북구', - KBK: '강북구', - TBG: '도봉구', - NWN: '노원구', - UPG: '은평구', - SDM: '서대문구', - MPO: '마포구', - YGC: '양천구', - KSS: '강서구', - KRO: '구로구', - KCN: '금천구', - YDP: '영등포', - TJK: '동작구', - KNK: '관악구', - SCO: '서초구', - KNM: '강남구', - SPA: '송파구', - KDG: '강동구', -}; +import { + convertDistrictCode, + setDistrict, + getDistrict, + findDistrictToName, + changeDistrictInfo, +} from './district'; -const convertDistrictCode = (code) => { - return codeMap[code]; +export { + convertDistrictCode, + setDistrict, + getDistrict, + findDistrictToName, + changeDistrictInfo, }; - -export { convertDistrictCode }; From 3f808f6de91e542c2beaa0d7382e7c33725d412d Mon Sep 17 00:00:00 2001 From: jong yoon Date: Mon, 9 Dec 2019 15:36:09 +0900 Subject: [PATCH 6/8] =?UTF-8?q?FIX:=20=EC=A7=80=EC=97=AD=EA=B5=AC=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EB=AA=A8=EB=93=88=ED=99=94=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B8=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 지역구 정보를 모듈화를 시켜 간단한 코드 수정 --- .../match/MatchRegistModal/index.jsx | 36 ++++--------------- client/src/contexts/Match/Context.jsx | 2 +- 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/client/src/components/match/MatchRegistModal/index.jsx b/client/src/components/match/MatchRegistModal/index.jsx index 0c3fe528..69ee9152 100644 --- a/client/src/components/match/MatchRegistModal/index.jsx +++ b/client/src/components/match/MatchRegistModal/index.jsx @@ -8,37 +8,12 @@ import 'react-times/css/classic/default.css'; import 'react-dates/lib/css/_datepicker.css'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faTimesCircle } from '@fortawesome/free-solid-svg-icons'; +import { getDistrict } from '../../../util'; import { MatchContext } from '../../../contexts/Match/Context'; import './index.scss'; -const seoulDistrict = [ - { korName: '종로구', engName: 'CNO' }, - { korName: '중 구', engName: 'CGS' }, - { korName: '용산구', engName: 'YSN' }, - { korName: '성동구', engName: 'SDG' }, - { korName: '광진구', engName: 'KJI' }, - { korName: '동대문구', engName: 'TDM' }, - { korName: '중랑구', engName: 'CNG' }, - { korName: '성북구', engName: 'SBK' }, - { korName: '강북구', engName: 'KBK' }, - { korName: '도봉구', engName: 'TBG' }, - { korName: '노원구', engName: 'NWN' }, - { korName: '은평구', engName: 'UPG' }, - { korName: '서대문구', engName: 'SDM' }, - { korName: '마포구', engName: 'MPO' }, - { korName: '양천구', engName: 'YGC' }, - { korName: '강서구', engName: 'KSS' }, - { korName: '구로구', engName: 'KRO' }, - { korName: '금천구', engName: 'KCN' }, - { korName: '영등포구', engName: 'YDP' }, - { korName: '동작구', engName: 'TJK' }, - { korName: '관악구', engName: 'KNK' }, - { korName: '서초구', engName: 'SCO' }, - { korName: '강남구', engName: 'KNM' }, - { korName: '송파구', engName: 'SPA' }, - { korName: '강동구', engName: 'KDG' }, -]; +const SEOUL_DISTRICT = getDistrict(); const MatchRegistModal = () => { const { matchState } = useContext(MatchContext); @@ -120,10 +95,10 @@ const DistrictSection = () => { name="matchRegistDistrict" className="match-register__select match-register__input" > - {seoulDistrict.map((district) => { + {Object.entries(SEOUL_DISTRICT).map(([code, district]) => { return ( - ); })} @@ -200,6 +175,7 @@ const TimeSection = () => {
); }; + const TextInputSection = ({ title, idText, maxlen, required }) => { const [label, setLabel] = useState(''); const [value, setValue] = useState(''); diff --git a/client/src/contexts/Match/Context.jsx b/client/src/contexts/Match/Context.jsx index bbef6fbc..0ecfab3e 100644 --- a/client/src/contexts/Match/Context.jsx +++ b/client/src/contexts/Match/Context.jsx @@ -5,7 +5,7 @@ const initialState = { isViewRegistModal: false, }; -const MatchContext = createContext(initialState); +const MatchContext = createContext(null); const MatchProvider = ({ children }) => { const [matchState, dispatch] = useReducer(matchReducer, initialState); From f78af5aa6170c6cd9bacc5c1903bc10f1d986124 Mon Sep 17 00:00:00 2001 From: jong yoon Date: Mon, 9 Dec 2019 17:35:50 +0900 Subject: [PATCH 7/8] =?UTF-8?q?FIX:=20data=20fetch=20=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=B6=80=EB=B6=84=EC=9D=84=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=ED=9B=85=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fetch하는 부분이 계속되서 중복되므로 커스텀 훅으로 만들어 사용 --- .../src/components/match/MatchMap/index.jsx | 79 +++++++++++++------ client/src/hooks/useAsync.js | 54 +++++++++++++ 2 files changed, 107 insertions(+), 26 deletions(-) create mode 100644 client/src/hooks/useAsync.js diff --git a/client/src/components/match/MatchMap/index.jsx b/client/src/components/match/MatchMap/index.jsx index 138ef290..03a90805 100644 --- a/client/src/components/match/MatchMap/index.jsx +++ b/client/src/components/match/MatchMap/index.jsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import loadJs from 'load-js'; import axios from 'axios'; import MDSpinner from 'react-md-spinner'; +import useAsync from '../../../hooks/useAsync'; import { changeDistrictInfo, findDistrictToName } from '../../../util'; import './index.scss'; @@ -20,34 +21,59 @@ const markerElement = { }, }; -const MatchMap = () => { - const [naverMapData, setNaverMapData] = useState(); - const [seoulDistrictData, setSeoulDistrictData] = useState(); +const getNaverMap = async () => { + await loadJs(NAVER_MAP_API_REQUEST_URL); + return window.naver.maps; +}; - // data 요청 - useEffect(() => { - const fetchDatas = async () => { - await loadJs(NAVER_MAP_API_REQUEST_URL); - setNaverMapData(window.naver.maps); - const seoulDistrictResponse = await axios(SEOUL_DISTRICT_REQUEST_URL); - setSeoulDistrictData( - seoulDistrictResponse.data.response.result.featureCollection.features - ); - }; - fetchDatas(); - return () => { - setSeoulDistrictData(undefined); - setNaverMapData(undefined); - }; - }, []); +const getDistrcitData = async () => { + const response = await axios(SEOUL_DISTRICT_REQUEST_URL); + return response.data.response.result.featureCollection.features; +}; + +const MatchMap = () => { + const [naverMapState, reFetchNaverMap] = useAsync(getNaverMap, []); + const [seoulDistrictState, reFetchDisrictData] = useAsync( + getDistrcitData, + [] + ); + const { loading: mapLoading, data: mapData, error: mapError } = naverMapState; + const { + loading: districtLoding, + data: districtData, + error: districtError, + } = seoulDistrictState; + if (mapLoading || districtLoding) { + return ( +
+ +
+ ); + } + if (mapError) { + return ( +
+ +
+ ); + } + if (districtError) { + return ( +
+ +
+ ); + } + if (!mapData) return null; + if (!districtData) return null; return (
- {naverMapData && seoulDistrictData ? ( - - ) : ( - - )} +
); }; @@ -248,7 +274,7 @@ const NaverMap = (props) => { clickEvent(e.feature); }; - const handleDistrictMousemoveEvent = () => { + const handleDistrictOutEvent = () => { if (districtMarker) { districtMarker.setMap(null); } @@ -266,7 +292,8 @@ const NaverMap = (props) => { addEvent(false, naverMap.data, 'mouseover', handleDistrictMouseoverEvent); addEvent(false, naverMap.data, 'mouseout', handleDistrictMouseoutEvent); addEvent(false, naverMap.data, 'click', handleDistrictClickEvent); - addEvent(true, naverMap, 'mousemove', handleDistrictMousemoveEvent); + addEvent(true, naverMap, 'mousemove', handleDistrictOutEvent); + addEvent(true, naverMap, 'mouseout', handleDistrictOutEvent); } /* eslint react-hooks/exhaustive-deps: 0 */ }, [naverMap]); diff --git a/client/src/hooks/useAsync.js b/client/src/hooks/useAsync.js new file mode 100644 index 00000000..6704129d --- /dev/null +++ b/client/src/hooks/useAsync.js @@ -0,0 +1,54 @@ +/* eslint-disable indent */ +import { useReducer, useEffect } from 'react'; + +const reducer = (state, action) => { + // eslint-disable-next-line default-case + switch (action.type) { + case 'LOADING': + return { + loading: true, + data: null, + error: null, + }; + case 'SUCCESS': + return { + loading: false, + data: action.data, + error: null, + }; + case 'ERROR': + return { + loading: false, + data: null, + error: action.error, + }; + default: + throw new Error(`Unhandled action type: ${action.type}`); + } +}; + +const useAsync = (callback, deps) => { + const [state, dispatch] = useReducer(reducer, { + loading: false, + data: null, + error: null, + }); + + const fetchData = async () => { + dispatch({ type: 'LOADING' }); + try { + const data = await callback(); + dispatch({ type: 'SUCCESS', data }); + } catch (e) { + dispatch({ type: 'ERROR', error: e }); + } + }; + + useEffect(() => { + fetchData(); + }, deps); + + return [state, fetchData]; +}; + +export default useAsync; From de77091aa3dbe4b52f136aaa10684adb2566ce6e Mon Sep 17 00:00:00 2001 From: jong yoon Date: Mon, 9 Dec 2019 23:33:30 +0900 Subject: [PATCH 8/8] =?UTF-8?q?FIX:=20=EC=84=A0=ED=83=9D=EB=90=9C=20?= =?UTF-8?q?=EA=B5=AC=EB=93=A4=EA=B3=BC=20=ED=98=84=EC=9E=AC=20=EB=A7=88?= =?UTF-8?q?=EC=9A=B0=EC=8A=A4=20=EC=98=A4=EB=B2=84=EB=90=9C=20=EA=B5=AC=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 선택된 구들은 전역으로 쓰일 수 있기 때문에 context에 저장 현재 오버된 구를 useState로 관리 state로 관리하므로 이벤트 핸들러 함수 변경 reducer와 actions 분리 --- .../src/components/match/MatchMap/index.jsx | 132 ++++++++++-------- .../components/match/MatchRegist/index.jsx | 6 +- client/src/contexts/Match/Actions.js | 7 + client/src/contexts/Match/Context.jsx | 1 + client/src/contexts/Match/Reducer.js | 38 +++-- 5 files changed, 115 insertions(+), 69 deletions(-) create mode 100644 client/src/contexts/Match/Actions.js diff --git a/client/src/components/match/MatchMap/index.jsx b/client/src/components/match/MatchMap/index.jsx index 03a90805..aa50426e 100644 --- a/client/src/components/match/MatchMap/index.jsx +++ b/client/src/components/match/MatchMap/index.jsx @@ -1,9 +1,11 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useContext } from 'react'; import loadJs from 'load-js'; import axios from 'axios'; import MDSpinner from 'react-md-spinner'; import useAsync from '../../../hooks/useAsync'; import { changeDistrictInfo, findDistrictToName } from '../../../util'; +import { MatchContext } from '../../../contexts/Match/Context'; +import matchActions from '../../../contexts/Match/Actions'; import './index.scss'; const NAVER_MAP_API_REQUEST_URL = `https://openapi.map.naver.com/openapi/v3/maps.js?ncpClientId=${process.env.REACT_APP_NCP_CLIENT_ID}`; @@ -82,6 +84,8 @@ const NaverMap = (props) => { /* eslint react/prop-types: 0 */ const { mapData, districtData } = props; const [naverMap, setNaverMap] = useState(undefined); + const { matchState, dispatch } = useContext(MatchContext); + const [curMarker, setCurMarker] = useState([]); const createMapTitleMarker = () => { return new mapData.Marker({ @@ -111,6 +115,10 @@ const NaverMap = (props) => { const defaultOption = { strokeOpacity: 1, strokeWeight: 2, + fillColor: '#71ACAD', + fillOpacity: 0.6, + strokeColor: '#71ACAD', + zIndex: 4, }; /* eslint indent: ["error", 2, { "SwitchCase": 1 }] */ switch (action) { @@ -131,13 +139,7 @@ const NaverMap = (props) => { zIndex: 6, }; default: - return { - ...defaultOption, - fillColor: '#71ACAD', - fillOpacity: 0.6, - strokeColor: '#71ACAD', - zIndex: 4, - }; + return defaultOption; } }; @@ -154,18 +156,15 @@ const NaverMap = (props) => { }; // 현재 마우스 이벤트에 따라 나오는 마커 - let districtMarker; - // 선택한 지역구의 마커들 - let selectedDistrictMarker = {}; - + // let districtMarker; const showSelectedDistrictMarker = () => { - Object.values(selectedDistrictMarker).forEach((marker) => { + Object.values(matchState.selectedDistricts).forEach((marker) => { marker.setMap(naverMap); }); }; const hideAllDistrictMarker = () => { - Object.values(selectedDistrictMarker).forEach((marker) => { + Object.values(matchState.selectedDistricts).forEach((marker) => { marker.setMap(null); }); }; @@ -181,7 +180,6 @@ const NaverMap = (props) => { const mouseoutEvent = (target) => { const curDistrictName = target.property_sig_kor_nm; - showSelectedDistrictMarker(); if (findDistrictToName(curDistrictName).isSelected) { return; } @@ -189,29 +187,26 @@ const NaverMap = (props) => { }; const deleteMarkerInSelectedMarkers = (curDistrictName) => { - if (!selectedDistrictMarker[curDistrictName]) { + if (!matchState.selectedDistricts[curDistrictName]) { return; } - const newMarkers = {}; - Object.entries(selectedDistrictMarker).forEach(([name, marker]) => { - if (name !== curDistrictName) { - newMarkers[name] = marker; - } + dispatch({ + type: matchActions.DELETE_SELECT_DISTRICT, + payload: { curDistrictName }, }); - selectedDistrictMarker = { ...newMarkers }; }; const insertMarkerInSelectedMarkers = (curDistrictName) => { - if (selectedDistrictMarker[curDistrictName]) { + if (matchState.selectedDistricts[curDistrictName]) { return; } - const newMarkers = { ...selectedDistrictMarker }; - newMarkers[curDistrictName] = districtMarker; - selectedDistrictMarker = { ...newMarkers }; + dispatch({ + type: matchActions.INSERT_SELECT_DISTRICT, + payload: { curMarker, curDistrictName }, + }); }; const clickEvent = (target) => { - hideAllDistrictMarker(); const curDistrictName = target.property_sig_kor_nm; const preTargetInfo = { ...findDistrictToName(curDistrictName) }; preTargetInfo.isSelected = !preTargetInfo.isSelected; @@ -224,44 +219,34 @@ const NaverMap = (props) => { ? insertMarkerInSelectedMarkers : deleteMarkerInSelectedMarkers; processMarkerAction(curDistrictName); - showSelectedDistrictMarker(); }; // 지역구 이름 마커 생성 함수 const createDistrictNameMarker = (district) => { const curDistrictName = district.property_sig_kor_nm; const districtInfo = findDistrictToName(curDistrictName); - districtMarker = new mapData.Marker({ - position: new mapData.LatLng( - districtInfo.namePosition.y, - districtInfo.namePosition.x - ), - clickable: true, - icon: { - content: markerElement.districtName(curDistrictName), - }, - map: naverMap, + setCurMarker((pre) => { + const newMaker = new mapData.Marker({ + position: new mapData.LatLng( + districtInfo.namePosition.y, + districtInfo.namePosition.x + ), + clickable: true, + icon: { + content: markerElement.districtName(curDistrictName), + }, + map: naverMap, + district, + }); + if (pre.length > 0) { + pre[0].setMap(null); + } + return [newMaker]; }); - addEvent( - true, - districtMarker, - 'mouseover', - mouseoverEvent.bind(null, district) - ); - addEvent( - true, - districtMarker, - 'mouseout', - mouseoutEvent.bind(null, district) - ); - addEvent(true, districtMarker, 'click', clickEvent.bind(null, district)); }; // 지역구에 등록할 이벤트 const handleDistrictMouseoverEvent = (e) => { - if (districtMarker) { - districtMarker.setMap(null); - } mouseoverEvent(e.feature); createDistrictNameMarker(e.feature); }; @@ -275,11 +260,44 @@ const NaverMap = (props) => { }; const handleDistrictOutEvent = () => { - if (districtMarker) { - districtMarker.setMap(null); - } + setCurMarker((prev) => { + if (prev.length > 0) { + prev[0].setMap(null); + } + return [...prev]; + }); }; + useEffect(() => { + console.log(curMarker); + if (curMarker.length === 0) { + return; + } + addEvent( + true, + curMarker[0], + 'mouseover', + mouseoverEvent.bind(null, curMarker[0].district) + ); + addEvent( + true, + curMarker[0], + 'mouseout', + mouseoutEvent.bind(null, curMarker[0].district) + ); + addEvent( + true, + curMarker[0], + 'click', + clickEvent.bind(null, curMarker[0].district) + ); + }, [curMarker]); + + useEffect(() => { + hideAllDistrictMarker(); + showSelectedDistrictMarker(); + }, [matchState]); + useEffect(() => { if (naverMap === undefined) { setNaverMap(new mapData.Map('map', mapInitOptions)); diff --git a/client/src/components/match/MatchRegist/index.jsx b/client/src/components/match/MatchRegist/index.jsx index 5127ba4e..645bd780 100644 --- a/client/src/components/match/MatchRegist/index.jsx +++ b/client/src/components/match/MatchRegist/index.jsx @@ -1,13 +1,13 @@ import React, { useContext } from 'react'; import { MatchContext } from '../../../contexts/Match/Context'; +import matchActions from '../../../contexts/Match/Actions'; import './index.scss'; const MatchRegist = () => { - const { matchState, dispatch } = useContext(MatchContext); + const { dispatch } = useContext(MatchContext); const handleMatchRegisterBtn = () => { dispatch({ - type: 'TOGGLE_VIEW_MATCH_REGIST_MODAL', - isViewRegistModal: matchState.isViewRegistModal, + type: matchActions.TOGGLE_VIEW_MATCH_REGIST_MODAL, }); }; diff --git a/client/src/contexts/Match/Actions.js b/client/src/contexts/Match/Actions.js new file mode 100644 index 00000000..f2865b24 --- /dev/null +++ b/client/src/contexts/Match/Actions.js @@ -0,0 +1,7 @@ +const actions = { + TOGGLE_VIEW_MATCH_REGIST_MODAL: 'TOGGLE_VIEW_MATCH_REGIST_MODAL', + INSERT_SELECT_DISTRICT: 'INSERT_SELECT_DISTRICT', + DELETE_SELECT_DISTRICT: 'DELETE_SELECT_DISTRICT', +}; + +export default actions; diff --git a/client/src/contexts/Match/Context.jsx b/client/src/contexts/Match/Context.jsx index 0ecfab3e..94a06176 100644 --- a/client/src/contexts/Match/Context.jsx +++ b/client/src/contexts/Match/Context.jsx @@ -3,6 +3,7 @@ import matchReducer from './Reducer'; const initialState = { isViewRegistModal: false, + selectedDistricts: {}, }; const MatchContext = createContext(null); diff --git a/client/src/contexts/Match/Reducer.js b/client/src/contexts/Match/Reducer.js index 3a714d3e..8546a4df 100644 --- a/client/src/contexts/Match/Reducer.js +++ b/client/src/contexts/Match/Reducer.js @@ -1,17 +1,37 @@ -const toggleViewMatchRegistModal = (state, isView) => { - return { - ...state, - isViewRegistModal: !isView, - }; -}; +import matchActions from './Actions'; const matchReducer = (state, action) => { /* eslint indent: ["error", 2, { "SwitchCase": 1 }] */ switch (action.type) { - case 'TOGGLE_VIEW_MATCH_REGIST_MODAL': - return toggleViewMatchRegistModal(state, action.isViewRegistModal); + case matchActions.TOGGLE_VIEW_MATCH_REGIST_MODAL: + return { + ...state, + isViewRegistModal: !state.isViewRegistModal, + }; + case matchActions.INSERT_SELECT_DISTRICT: { + const { districtMarker, curDistrictName } = action.payload; + const newMarkers = { ...state.selectedDistricts }; + newMarkers[curDistrictName] = districtMarker; + return { + ...state, + selectedDistricts: newMarkers, + }; + } + case matchActions.DELETE_SELECT_DISTRICT: { + const { curDistrictName } = action.payload; + const newMarkers = {}; + Object.entries(state.selectedDistricts).forEach(([name, marker]) => { + if (name !== curDistrictName) { + newMarkers[name] = marker; + } + }); + return { + ...state, + selectedDistricts: newMarkers, + }; + } default: - throw new Error('Unhandled action!'); + throw new Error(`Unhandled action type: ${action.type}`); } };