Why does renderToString throws error about useLayoutEffect while rendering Material-UI component?
Asked Answered
F

1

7

I am using React v.16.12.0 and @MaterialUI/core v4.8.1.

I am trying to create custom icon for React Leaflet Marker. The icon is a Fab component from Material-UI. To do that, I need to pass a HTML string to L.DivIcon (DivIcon Docs) Leaflet component, so I am using renderToString() method from react-dom/server.

And it is throwing an error:

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. in NoSsr in button in ForwardRef(ButtonBase) in WithStyles(ForwardRef(ButtonBase)) in ForwardRef(Fab) in WithStyles(ForwardRef(Fab)) (at src/index.js:9)

While I'm not using useLayoutEffect.

Here's a simple example:

import React from "react";
import ReactDOM from "react-dom";
import ReactDOMServer from 'react-dom/server';
import Fab from '@material-ui/core/Fab';

function App() {
  return ReactDOMServer.renderToString(
    <Fab size="small" variant="extended">
      Test
    </Fab>);
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Online: https://codesandbox.io/s/material-ui-rendertostring-tc90b

Why is it throwing that error? What's incorrect with this code? Is there any other way to generate HTML-String from Material-UI Component in order to pass it as an icon to Leaflet Marker?

Flabbergast answered 25/12, 2019 at 16:53 Comment(6)
what happens if you save it to a variable on console.log it? HERES A CODE SNIPPET: import React from "react"; import ReactDOM from "react-dom"; import ReactDOMServer from 'react-dom/server'; import Fab from '@material-ui/core/Fab'; function App() { let test = ReactDOMServer.renderToString( <Fab size="small" variant="extended"> Test </Fab>); console.log(test); } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);Rebozo
It logs HTMLString correctly. The snippet provided in the question also returns correct HTMLString but it throws an error. I'm trying to add ~thousand of markers to the map and every marker has a custom icon made using renderToString which throws this error.Flabbergast
Your sandbox does not contain any code relevant to your questionHematite
Ouch, sorry, it should work now.Flabbergast
L.icon seems to not have the functionality that your looking for. You must pass in a URL and not HTML. leafletjs.com/reference-1.6.0.html#icon-optionRebozo
I'm sorry, my fault. I meant L.DivIcon, not L.Icon. I updated the question and added link to Leaflet docs.Flabbergast
I
-2

I used renderToStaticMarkup to render a custom marker. Marker is getting rendered but still getting the warnings.

import React, { Component } from "react";
import ReactDOM from "react-dom";
import { renderToStaticMarkup } from "react-dom/server";
import { divIcon } from "leaflet";
import { Map, TileLayer, Marker, Popup } from "react-leaflet";
import Fab from "@material-ui/core/Fab";

import "./styles.css";

class App extends Component {
  state = {
    lat: 51.505,
    lng: -0.091,
    zoom: 13
  };

  render() {
    const position = [this.state.lat, this.state.lng];
    const iconMarkup = renderToStaticMarkup(
      <Fab size="small" variant="extended">
        Test
      </Fab>
    );
    const customMarkerIcon = divIcon({
      html: iconMarkup
    });

    return (
      <div>
        <Map center={position} zoom={this.state.zoom}>
          <TileLayer
            attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
            url="https://{s}.tile.osm.org/{z}/{x}/{y}.png"
          />
          <Marker position={position} icon={customMarkerIcon}>
            <Popup>
              A pretty CSS3 popup. <br /> Easily customizable.
            </Popup>
          </Marker>
        </Map>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Working code: https://codesandbox.io/s/react-leaflet-icon-material-mx1iu

Ingles answered 31/12, 2019 at 10:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.