A매장 Marker를 클릭하면 Circle이 나타나면서 Circle 반경 안에있는 장소의 pin만 나타내고 싶다.
하지만 A매장 Marker를 클릭하면 pin이 안나오다가 B매장 Marker를 클릭하면 A매장에 해당하는 pin이 나타나고 C매장 Marker를 클릭하면 B매장에 해당하는 pin이 나타난다.
즉, data가 하나씩 밀려서 나타난다.
const [deliveryData, setDeliveryData] = useState([]);
const [inRange, setInRange] = useState([]);
const handleClickMarker = marker => {
setSelectedMarkerId(marker.id);
setOpenCircle(!openCircle);
fetch(`http://서버/deliveries?store=${marker.name}`)
.then(res => res.json())
.then(data => {
setDeliveryData(data.result)
});
const filtered = deliveryData.filter(
spot =>
getDistance(
{
latitude: marker.x_coordinate,
longitude: marker.y_coordinate,
},
{
latitude: spot.y_coordinate,
longitude: spot.x_coordinate,
}
) <= 1000
);
setDeliveryData(filtered);
};
{deliveryData &&
openCircle &&
deliveryData.map(data => (
<div key={data.id}>
<Marker
position={
new navermaps.LatLng(data.y_coordinate,data.x_coordinate)}
icon={{
content: `<div class="pin">
<i class="fa-solid fa-location-pin"></i>
</div>`}}
title="배달지"
/>
</div>
))}
문제
A매장을 클릭하면 아무것도 안나온다.
2번 클릭하면 나온다
그 후 C 매장을 누르면 A매장에 해당하는 배달지 마커가 찍힌다.
한 번 더 클릭하면 C 매장에 해당하는 배달지 마커가 찍힌다.
이렇게 불러와지는 데이터가 한박자 늦게 화면에 구성된다.
오케 그럼 어떻게 해야할까? 구글에 검색하니 해결책이 나온다
- useEffect를 사용해서 의존성 배열에 state를 넣어라
=> 이 방법은 url 주소 변경할 때 사용한 적이 있다.
1번이 부적격인 이유
useEffect는 함수안에 작성할 수 없다. 하지만 onclick함수에서 이 모든 일이 일어나기 위해 handleClickMarker 안에 작성하고 싶다.
useEffect를 함수 밖에 작성하면 인수를 전해줄 수 없다. 즉 클릭되는 버튼에 담긴 데이터를 넘겨줄 수 없다
- useState를 사용할 때 state를 업데이트 하기 위해서는 callback 함수로 이전값을 명시하자
=>setData(count + 1) => (x)
=>setData(prevCount + 1) => (o)
2번이 부적격인 이유
위의 예시로 단순히 count에 1을 더하는 간단한 식은 가능할지도 모른다.
하지만 만약 count를 업데이트 시키는 방법과 현재 내가 작성한 코드에서 위의 방법으로 어떻게 적용해야 하는지 모르겠다. 일단 데이터에서 넘겨받는 인수는 어디에 작성하며 + 1이 아닌 map 함수 안에 있는 즉, 같은 state 안의 다른 요소를 어떻게 가져올 수 있을까...
- spread 연산자를 사용한다.
=> 받아오는 데이터가 배열이기 때문에 데이터를 직접 수정하기 보다는 깊은 복사를 통해서 변경한다.
=>setData([...deliveryData, deliveryData])
3가지 꾸역꾸역 작성했지만 실패...문제가 해결되지는 않았다.
애초에 데이터를 state에 저장하는 것이 아니라 변수 그대로 filter를 사용한다.
const [deliveryData, setDeliveryData] = useState([]);
const handleClickMarker = marker => {
setSelectedMarkerId(marker.id);
setOpenCircle(!openCircle);
fetch(`http://43.200.4.19:80/deliveries?store=${marker.name}`)
.then(res => res.json())
.then(data => {
const filtered = data.result.filter(
//굳이 원본 데이터부터 setState에 담지 않아도 된다.
spot =>
getDistance(
{
latitude: marker.x_coordinate,
longitude: marker.y_coordinate,
},
{
latitude: spot.y_coordinate,
longitude: spot.x_coordinate,
}
) <= 1000 //1km(m단위로 작성)
);
setDeliveryData(filtered);
});
};
{deliveryData &&
openCircle &&
deliveryData.map(data => (
<div key={data.id}>
<Marker
position={new navermaps.LatLng(data.y_coordinate, Data.x_coordinate)}
icon={{
content: `<div class="pin">
<i class="fa-solid fa-location-pin"></i>
</div>`}}
title="배달지"
/>
</div>
))}
useState의 초기값은 빈 배열이다. 따라서 처음 화면에서 state에 담긴 값이 []
이라는 것
지금 fetch를 작성해서 받아온 데이터도 어차피 배열이니 바로 filter를 돌리자
그랬더니...처음부터 데이터가 담기면서 데이터가 밀려서 나오지 않고 제대로 나온다.
결과적으로 처음에 서버에서 데이터를 받아올 때 state에 저장하는 것이 아니라 data라는 변수에 저장하고 해당 변수를 바로 filter를 적용하여 원하는 데이터만 뽑아내 사용한다.
다양한 방법을 사용해도 자꾸 이전의 값만 사용하라는 해결방안만 제시할 뿐 딱히 도움되는 검색결과가 없어 힘들었다.
코드는 한 끝 차이라고 생각한다. 필승법처럼 먹힐 것 같은 방법도 조금 다른 코드에서는 먹히지 않는다.
state에 담지 않는 방법 외에도 이를 해결할 방안이 있을 것 같은데 아직은 찾지 못했다... 아쉽다...