Reputation: 317
The problem is that every time I hover on a marker a popup is opened or closed and it causes all the markers to re-render even though my state is not changing. console.log(myState);
is running every time I hover in and out of the marker.
I tried to use useMemo hook but couldn't figure out how to use it on country.map
. Any help?
Here is my code:
import React, { useEffect, useState } from 'react';
import { Map, TileLayer, Marker, Popup } from 'react-leaflet';
import axios from 'axios';
import { v4 as uuidv4 } from 'uuid';
import { Icon } from 'leaflet';
const myicon = new Icon({
iconUrl: './icon.svg',
iconSize: [20, 20]
});
const MyMap = () => {
const [myState, setMyState] = useState(null);
const [activePlace, setActivePlace] = useState(null);
const getData = async () => {
let response = await axios
.get('https://corona.lmao.ninja/v2/jhucsse')
.catch(err => console.log(err));
let data = response.data;
setMyState(data);
// console.log(data);
};
useEffect(() => {
getData();
}, []);
if (myState) {
console.log(myState);
return (
<Map
style={{ height: '100vh', width: '100vw' }}
center={[14.561, 17.102]}
zoom={1}
>
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>'
url={
'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png'
}
/>
{myState.map(country => {
return (
<Marker
key={uuidv4()}
position={[
country.coordinates.latitude,
country.coordinates.longitude
]}
onmouseover={() => {
setActivePlace(country);
}}
onmouseout={() => {
setActivePlace(null);
}}
icon={myicon}
/>
);
})}
{activePlace && (
<Popup
position={[
activePlace.coordinates.latitude,
activePlace.coordinates.longitude
]}
>
<div>
<h4>Country: {activePlace.country}</h4>
</div>
</Popup>
)}
</Map>
);
} else {
return <div>Nothing</div>;
}
};
export default MyMap;
Upvotes: 0
Views: 2729
Reputation: 4065
Do you even need myState to be state? Can it just be a regular variable? That would solve your issue right away. If not, make a copy of myState, and then run map() with that. You will also need a flag to determine whether or not to run the map
function, so setup a runMap
state hook:
const MyMap = () => {
// *** Create a FLAG for the map() call
const [runMap, setRunMap] = useState(false);
const [activePlace, setActivePlace] = useState(null);
// setup the data to be function-scoped
let data;
const getData = async () => {
let response = await axios
.get('https://corona.lmao.ninja/v2/jhucsse')
.catch(err => console.log(err));
// just use the data here
data = response.data;
// set your runMap flag
setRunMap(true);
}
// later on...
if (runMap) {
// ...
{data.map(country => {
As a side-note, you aren't supposed to be calling hooks this way, inside of nested functions and all. They are supposed to be called at the top-level of the component. There are a bunch of rules honestly, in your case it seems like using a class-based component and replacing your useEffect
hook with componentDidMount
might be safer, with the downside of being more verbose.
Upvotes: 1