Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support server-side rendering #45

Closed
dmitry opened this issue Jun 25, 2015 · 17 comments
Closed

Support server-side rendering #45

dmitry opened this issue Jun 25, 2015 · 17 comments

Comments

@dmitry
Copy link

dmitry commented Jun 25, 2015

https://github.com/PaulLeCam/react-leaflet#technical-considerations have the following point:

Leaflet makes direct calls to the DOM when it is loaded, therefore this library is not compatible with server-side rendering.

I would like to discuss of the possibilities how it's possible to add server-side support for this library.

My current solution just skip rendering the leaflet on server-side, and render just on client-side:

  render() {
    const position = [51.505, -0.09];

    if (process.env.BROWSER) {
      var {Map, Marker, Popup, TileLayer} = require('react-leaflet');
      return (
        <div className="search-map">
          <Map center={position} zoom={13}>
            <TileLayer
              url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
              attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
              />
            <Marker position={position}>
              <Popup>
                <span>A pretty CSS3 popup.<br/>Easily customizable.</span>
              </Popup>
            </Marker>
          </Map>
        </div>
      );
    }
    else {
      return null;
    }
  }

I don't believe it's a best practice, but still it's something, than nothing, and I think it's better than using the headless-leaflet fork.

@PaulLeCam
Copy link
Owner

PaulLeCam commented Jun 26, 2015

The issue is with Leaflet itself, as it doesn't check if the DOM is available when it's loaded, not directly this library.
I do not plan to support server-side rendering in this lib until it is supported by Leaflet itself, unless it's a trivial implementation with no side-effect.

The solution you presented may work for you, but it's completely dependant on your environment and your build, it would probably not work in other cases.

@iam4x
Copy link

iam4x commented Jul 17, 2015

@PaulLeCam We could provide a React Component as fallback for server side rendering, check if window exists render the map or render the fallback? Something like that:

<Map .... fallback={ReactComponent}>
  ...
</Map>

@PaulLeCam
Copy link
Owner

@iam4x Feel free to implement any workaround in your app... As I previously explained, this issue is not caused by this lib.

@dougajmcdonald
Copy link

Thanks for the workarounds gents, I ended up just using a client side bower package and not the react package, but will switch back now I know the render could be defined conditionally based on the environment

@dmitry
Copy link
Author

dmitry commented Sep 15, 2015

@dougajmcdonald similar idea I'm using too. It's more flexible and maintainable.

@josebalius
Copy link

@dougajmcdonald I was wondering what was the solution for this? You guys are loading leaflet in with bower, and then proceeding to require react-leaflet the same way? Or are you guys also using bower to load react-leaflet?

@sohibul
Copy link

sohibul commented Nov 1, 2016

May someone give the example of this workaround

@jgimbel
Copy link
Contributor

jgimbel commented Nov 1, 2016

It's ugly, but it works.

let Map, MapComponents
class LeafletMap extends Component {

  componentDidMount(){
    //Only runs on Client, not on server render
    Map = require('react-leaflet').Map
    MapComponents = require('./mapComponents').default
    this.forceUpdate()
  }

  render () {
    return (
      (Map)
      ? (
        <Map
          zoom={10}
          maxZoom={18}
          minZoom={9}
        >
          <MapComponent />
        </Map>
      )
      : (null)
      }
    )
  }
}

@stereobooster
Copy link

For future googlers, there is also https://github.com/masotime/react-leaflet-universal

And some attempts to render leaflet on the server:

@rktel
Copy link

rktel commented Aug 31, 2017

it works, too.

In index.html:

Include ..rel="stylesheet" href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css"..

In React Component

`import React, { Component } from 'react'

class Mapa extends Component {

componentWillMount() {
    console.log('componentWillMount')
    Map = require('react-leaflet').Map
    TileLayer = require('react-leaflet').TileLayer
    TileLayer = require('react-leaflet').TileLayer
    Marker = require('react-leaflet').Marker
    Popup = require('react-leaflet').Popup
}

render() {
    const position = [-12.76767, -76.343434]
    return (

            <Map center={position} zoom={10} style={{ height: "100vh" }}>
                <TileLayer
                    attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                    url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
                />
                <Marker position={position}>
                    <Popup>
                        <span>A pretty CSS3 popup. <br /> Easily customizable.</span>
                    </Popup>
                </Marker>
            </Map>


    )
}

}

export default Mapa`

@revolunet
Copy link

The cleanest solution i found is here : https://github.com/etalab/adresse.data.gouv.fr/blob/0bc6dd7/pages/map.js#L5-L12

@quangmydn
Copy link

rktel how to extends MapControl with componentWillMount().
I want add search box by https://github.com/smeijer/leaflet-geosearch.

@owlyowl
Copy link

owlyowl commented Aug 29, 2019

For anyone wondering I managed to get this working using react-loadable for now

In your parent component do something like so:
const LoadableSearchResultMap = Loadable({ loader: () => import('./SearchResultMap') as Promise<any>, loading() { return <div>Loading...</div> } });

Then I made a component called SearchResultMap.tsx and inside is:

`import * as React from 'react';
import { Map, Marker, Popup, TileLayer, LayersControl } from 'react-leaflet';
import ReactLeafletGoogleLayer from 'react-leaflet-google-layer';
import { LatLngExpression } from 'leaflet';

export default class SearchResultMap extends React.Component {
mapSettings = {
zoom: 15,
center: [48.067539, 12.862530] as LatLngExpression
}

render() {
    return <><Map {...this.mapSettings}><ReactLeafletGoogleLayer googleMapsLoaderConf={{ KEY: 'Key Goes Here' }} type={'terrain'} /></Map></>
}

}`

@SOLUTRAFFICDEVELOPERALPHA

The cleanest solution i found is here : https://github.com/etalab/adresse.data.gouv.fr/blob/0bc6dd7/pages/map.js#L5-L12

Sorry, but how i pass props with this dynamic

@Kaz-z
Copy link

Kaz-z commented Jun 11, 2020

Hopefully this will help someone...If you're using gatsby then for some reason using the react-leaflet gatsby plugin works rather than using the library straight...weird but it saved me a lot of headache.

@bahmannejati
Copy link

bahmannejati commented Nov 3, 2020

This might be helpful for those who use Webpack & es6 dynamic import feature:

import React, { PureComponent } from 'react';

class MapLoader extends PureComponent {
  constructor(props) {
    super(props);

    this.state = { loading: true };
    this.Map= null;
  }

  componentDidMount() {
    import(/* webpackMode: "eager" */ './Map').then((module) => {
      this.Map = module.default;
      this.setState({ loading: false });
    });
  }

  render() {
    const { Map, props, state: { loading } } = this;

    if (loading) {
       return null;// or render a loading
    }

    return <Map {...props} />;
  }
}

export default MapLoader;

@walliby
Copy link

walliby commented Dec 1, 2023

This worked for me in React 18. MyMap is the component that has the leaflet imports. Then you can use Suspense if you want to render something else while it is importing.

const MyMap = React.lazy(() => import('./MyMap'));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests