I’m using leaflet and react-leaflet libraries to create a map inside a React Js app as well as Material UI library for the core UI components.
I’m creating a custom cluster and marker components (using React component, not using image/icon file) for the cluster and marker inside the map. I’m using react-leaflet-markercluster for the custom cluster feature and the pie chart from Apache Echarts library for the custom cluster component.
Problem
The problem I’m facing is the useEffect
hook inside my CustomCluster
component is never triggered.
Steps to produce
- Run the playground here: https://codesandbox.io/s/stackoverflow-custom-cluster-react-leaflet-s2wwsh
- This is the initial state
- Press the zoom out button (top left corner)
We can see that the 3 markers become a single cluster. The console prints thecluster
value from theCustomCluster
component but there is no “update chart” message. It means that theuseEffect
hook is not triggered. - Press again the zoom out button
We can see that all 4 markers become a single cluster. The console prints the updatedcluster
value from theCustomCluster
component but again there is no “update chart” message. It means that theuseEffect
hook is not triggered again.
Code
App.jsx
const customClusterIcon = (cluster, dummyLocationList) => {
return L.divIcon({
// className: 'marker-cluster-custom',
// html: `<span>${cluster.getChildCount()}</span>`,
// iconSize: L.point(40, 40, true),
className: "custom-icon",
html: ReactDOMServer.renderToString(
<ThemeProvider theme={customTheme}>
<StyledEngineProvider injectFirst>
<CustomCluster cluster={cluster} locationList={dummyLocationList} />
</StyledEngineProvider>
</ThemeProvider>
)
});
};
<MarkerClusterGroup
showCoverageOnHover={false}
spiderfyDistanceMultiplier={2}
iconCreateFunction={(cluster) =>
customClusterIcon(cluster, dummyLocationList)
}
>
{dummyLocationList.map((item, index) => (
<Marker
key={index}
position={[item.latitude, item.longitude]}
icon={L.divIcon({
className: "custom-icon",
html: ReactDOMServer.renderToString(
<ThemeProvider theme={customTheme}>
<StyledEngineProvider injectFirst>
<CustomMarker
movingStatus={item.status}
label={item.deviceName}
/>
</StyledEngineProvider>
</ThemeProvider>
)
})}
/>
))}
</MarkerClusterGroup>
CustomCluster.jsx
const CustomCluster = (props) => {
const { cluster, locationList } = props;
const classes = useStyles();
const chartRef = useRef();
let clusterLocationList = [];
cluster.getAllChildMarkers().forEach((itemCluster) => {
locationList.forEach((itemLocation) => {
if (
itemCluster._latlng.lat === itemLocation.latitude &&
itemCluster._latlng.lng === itemLocation.longitude
)
clusterLocationList.push(itemLocation);
});
});
const chartOption = {
series: [
{
name: "Access From",
type: "pie",
radius: ["40%", "70%"],
avoidLabelOverlap: false,
label: {
show: true,
position: "inner"
},
labelLine: {
show: false
},
data: [
{ value: 1048, name: "Search Engine" },
{ value: 735, name: "Direct" },
{ value: 580, name: "Email" },
{ value: 484, name: "Union Ads" },
{ value: 300, name: "Video Ads" }
]
}
]
};
useEffect(() => {
console.log("update chart");
let chart;
if (chartRef.current !== null) chart = init(chartRef.current);
const resizeChart = () => {
chart?.resize();
};
window.addEventListener("resize", resizeChart);
if (chartRef.current !== null) {
const chart = getInstanceByDom(chartRef.current);
chart.setOption(chartOption);
}
return () => {
chart?.dispose();
window.removeEventListener("resize", resizeChart);
};
}, [cluster]);
console.log(cluster);
return (
<>
{/* AVATAR */}
<Avatar>{cluster.getChildCount()}</Avatar>
{/* PIE CHART */}
<Box className={classes.chartContainer}>
<Box ref={chartRef} className={classes.chart} />
</Box>
</>
);
};
export default CustomCluster;
Question
Based on some articles on the internet, the useEffect
hook is not triggered on React server-side render (SSR) for example here https://codewithhugo.com/react-useeffect-ssr/.
So what’s the solution for this case?
The goal is to create a custom cluster feature using a pie chart.