Hey guys! Forgive me if this question has been asked before, but I've looked around and I'm stumped. This is my first react app, and I have turned mapbox draw polygons into a geojson, added editable properties (eg height with a slider) so it updates the geojson, then this is set as the geojson layer data. See below:
<GeoJSONLayer
id="draw_layer"
data={this.state.drawnBuilding}
fillExtrusionPaint={{
'fill-extrusion-color': {
'type': 'identity',
'property': 'colour'
},
'fill-extrusion-height': {
'type': 'identity',
'property': 'height'
},
'fill-extrusion-base': {
'type': 'identity',
'property': 'base_height'
}
}}
/>
I have previously had the fillExtrusionPaint properties set with states, and they updated live, but was applied to the whole layer. However, I need to be able to control individual polygon properties eg setting different heights for different polygons. My geojson currently does this and is a valid geojson, but the style properties are not re-rendered on the map. Is there an event that can make the map re-render when the source changes? I have the current version (2.7.0) and the new update didn't help the problem for me.
Thanks!
Madeleine
I have run into this problem as well trying to replicate the mapbox-gl example here: https://www.mapbox.com/mapbox-gl-js/example/measure/
GeoJSONLayer from react-mapbox-gl does not support dynamic source data, but I have figured out a workaround. You need to manually update the source data in the map instance by using the componentWillUpdate lifecycle method. First though, you'll need to store a reference to the map instance in your state using the onStyleLoad prop.
onStyleLoad = (map, e) => {
this.setState( {map} );
}
componentWillUpdate(nextProps, nextState) {
const { map, drawnBuilding } = nextState;
if (map) {
map.getSource('draw_layer').setData(drawnBuilding);
}
}
render() {
return (
<Map onStyleLoad={this.onStyleLoad}>
<GeoJSONLayer
id="draw_layer"
data={this.state.drawnBuilding}
fillExtrusionPaint={{
'fill-extrusion-color': { type: 'identity', property: 'colour' },
'fill-extrusion-height': { type: 'identity', property: 'height' },
'fill-extrusion-base': {
type: 'identity',
property: 'base_height'
}
}}
/>
</Map>
)
}
The GeoJSONLayer class should absolutely be performing the map.getSource(id).setData(data) step in its own lifecycle method.
So the reason it isn't working is that GeoJSONLayer only updates the data if the object reference is different to the previous prop passed in. https://github.com/alex3165/react-mapbox-gl/blob/master/src/geojson-layer.ts#L268
On componentWillReceiveProps it checks if (props.data !== data) { and if they are the same it will not update the data. This means it will not update the data if the top level object is the same even if there have been changes to the object itself.
The easiest way to make sure the object reference is new is to do const new drawnBuilding = Object.assign({}, drawnBuilding) when updating drawnBuilding and before you set your state so that the reference passed to the GeoJSONLayer component is new.
Closing, the question was answered
Hello I have a similar problem. I am not sure if someone can help me answer mine.
I am trying to code save/load function. I can say my save and load function works properly because it displays on console that for example when I load "Canada" file from database, it shows that Canada's properties.color has been changed from default color "green" to red. But it seems like I ran into an issue of not updating. How can this be fixed?
//Map.jsx
import React from 'react';
import { MapContainer, GeoJSON,} from "react-leaflet";
const Map = ({countries}) => {
const onEachCountry = (country, layer) => {
console.log(country.properties.color) //This shows me that some of the country colors has been changed
layer.options.fillColor = country.properties.color; // this should change the color of the map according to country.properties.color. But even after an update in country.properties.color, the color of the map does not change.
}
return (
<div>
<MapContainer>
<GeoJSON style = {countryStyle} data = {countries} onEachFeature={onEachCountry}/>{/*Displays the map */}
</MapContainer>
</div>
);
}
Most helpful comment
I have run into this problem as well trying to replicate the mapbox-gl example here: https://www.mapbox.com/mapbox-gl-js/example/measure/
GeoJSONLayer from react-mapbox-gl does not support dynamic source data, but I have figured out a workaround. You need to manually update the source data in the map instance by using the componentWillUpdate lifecycle method. First though, you'll need to store a reference to the map instance in your state using the onStyleLoad prop.
The GeoJSONLayer class should absolutely be performing the
map.getSource(id).setData(data)step in its own lifecycle method.