React-leaflet: GeoJSON data not rendered after change

Created on 25 May 2017  路  11Comments  路  Source: PaulLeCam/react-leaflet

Please make sure to check the following boxes before submitting an issue. Thanks!

  • [x] All peer dependencies are installed: React, ReactDOM and Leaflet.
  • [x] Using a supported version of React and ReactDOM (v15.0.0+).
  • [x] Using the supported version of Leaflet (v1.0.0) and its corresponding CSS file is loaded.
  • [x] Using the latest version of React-Leaflet.
  • [x] The issue has not already been reported.
  • [x] Make sure you have followed the quick start guide for Leaflet.
  • [x] Make sure you have fully read the documentation and that you understand the technical considerations.

Expected behavior

GeoJSON data should be re-rendered on the map after data prop change

Actual behavior

GeoJSON data rendered only once.

Steps to reproduce

Create custom component with Map and GeoJSON components. Pass prop from custom component to GeoJSON component. Change prop. See that old data still rendered.
ex: https://stackoverflow.com/questions/44155385/rendering-geojson-with-react-leaflet

Most helpful comment

Yet another workaround.

import React, { Component } from 'react';
import {GeoJSON} from 'react-leaflet';
import axios from 'axios';

import SymfonyRouterContext from './SymfonyRouterContext';

class ServiceGeoJson extends Component {

    constructor(props, context) {
        super(props, context);

        this.state = {
            data: []
        };

        this.geoJsonLayer = React.createRef();
    }

    componentDidMount() {

        const {service, params, zoom, center} = this.props;

        axios.post(this.context.generate(service, params), {zoom, center}).then(({data}) => {
            this.geoJsonLayer.current.leafletElement.clearLayers().addData(data);
            this.setState({data});
        });

    }

    render() {
        return <GeoJSON data={this.state.data} ref={this.geoJsonLayer}/>;
    }

}

ServiceGeoJson.contextType = SymfonyRouterContext;

export default ServiceGeoJson;

All 11 comments

This is the expected behavior, as documented.

@PaulLeCam Can you suggest how to achieve desired behavior?

You can set an unique key on the <GeoJSON> element every time you want it to be changed. In practice this will cause the existing layer to be removed from Leaflet and a new GeoJSON layer to be created with the provided data.

@PaulLeCam do you have a simple example of how can we implement your suggestion?

Thanks

There is nothing specific about it, it's just React behavior.
Put a different key on an element and it will be updated, in this case <GeoJSON key="whatever" data={geojson} /> for example.

Thanks man. I did something like that. But in my case it is not working. I sent you by twitter a piece of code.

Regards

I don't do support by Twitter, please use StackOverflow if you have questions regarding using the library.

This working behavior is useless. Changing key is just workaround.

I think <GeoJSON /> should act like React.PureComponent.

Yet another workaround.

import React, { Component } from 'react';
import {GeoJSON} from 'react-leaflet';
import axios from 'axios';

import SymfonyRouterContext from './SymfonyRouterContext';

class ServiceGeoJson extends Component {

    constructor(props, context) {
        super(props, context);

        this.state = {
            data: []
        };

        this.geoJsonLayer = React.createRef();
    }

    componentDidMount() {

        const {service, params, zoom, center} = this.props;

        axios.post(this.context.generate(service, params), {zoom, center}).then(({data}) => {
            this.geoJsonLayer.current.leafletElement.clearLayers().addData(data);
            this.setState({data});
        });

    }

    render() {
        return <GeoJSON data={this.state.data} ref={this.geoJsonLayer}/>;
    }

}

ServiceGeoJson.contextType = SymfonyRouterContext;

export default ServiceGeoJson;

Use ref worked out much smoother than using the component key and stopped the flashing on each update.

I implemented this with the useEffect and useRef hooks below (Note we do not need leafletElement):

const geoJsonLayer = useRef(null);

useEffect(() => {
    if (geoJsonLayer.current) {
      geoJsonLayer.current.clearLayers().addData(geoData);
    }
}, [geoData]);
...
<GeoJSON
    ref={geodataRef}
    // key={`${datakey}-main`}
     data={geoData}
    onEachFeature={onEachGeoFeature}
    style={featureStyling}
/>

Use ref worked out much smoother than using the component key and stopped the flashing on each update.

I implemented this with the useEffect and useRef hooks below (Note we do not need leafletElement):

const geoJsonLayer = useRef(null);

useEffect(() => {
    if (geoJsonLayer.current) {
      geoJsonLayer.current.clearLayers().addData(geoData);
    }
}, [geoData]);
...
<GeoJSON
    ref={geodataRef}
    // key={`${datakey}-main`}
     data={geoData}
    onEachFeature={onEachGeoFeature}
    style={featureStyling}
/>

Somehow this is not possible in version 3 or above.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ekatzenstein picture ekatzenstein  路  4Comments

thenickcox picture thenickcox  路  4Comments

acpower7 picture acpower7  路  4Comments

benzen picture benzen  路  4Comments

Shadowman4205 picture Shadowman4205  路  4Comments