useEffect hook isn’t triggered inside ReactDOMServer.renderToString()

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

  1. Run the playground here: https://codesandbox.io/s/stackoverflow-custom-cluster-react-leaflet-s2wwsh
  2. This is the initial state
    enter image description here
  3. Press the zoom out button (top left corner)
    enter image description here
    We can see that the 3 markers become a single cluster. The console prints the cluster value from the CustomCluster component but there is no “update chart” message. It means that the useEffect hook is not triggered.
  4. Press again the zoom out button
    enter image description here
    We can see that all 4 markers become a single cluster. The console prints the updated cluster value from the CustomCluster component but again there is no “update chart” message. It means that the useEffect 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.