Reputation: 287
How can I add the same marker in multiple Layers in react-leaflet?
For example:
I have an app to search for restaurants with react leaflet and every marker is a different restaurant. I want to have a LayerControl
to filter them by type and rating (1..5 stars).
I can have a LayerControl.Overlay
to filter by types (e.g. Buffet) but I also want to filter by rating. If I have a restaurant type='buffet' and rating=4 how can I do it for display the marker only when buffet type and 4 star rating are checked.
Here is my current code that filters only by type.
I'm using react-leaflet v3.
Upvotes: 0
Views: 1205
Reputation: 10676
The method you are using with creating various layergroups to manage your filters is not the best way to go about it. I took another approach.
In your App, create a state variable that holds potential filters. We'll set it to initially contain all options:
const restaurantTypes = ["Family Style", "Buffet", "Fast Food", "Cafe"];
const ratings = [1, 2, 3, 4, 5];
function App() {
const [filters, setFilters] = useState({
restaurantTypes,
ratings
});
...
}
I opted to create a custom component, which is basically the exact same html markup as a leaflet layercontrol, but without any of the functionality. You can check out the sandbox at the end of this answer, but all it does is manage the filters
state variable we just defined. Here's a brief summary:
const FilterControl = ({ filters, setFilters }) => {
return (
<div>
<h3>Type</h3>
{restaurantTypes.map((type) => (
<label>
<input
type="checkbox"
checked={filters.restaurantTypes.includes(type)}
onClick={(e) => {
if (filters.restaurantTypes.includes(type)) {
setFilters((prevFilters) => ({
...prevFilters,
restaurantTypes: prevFilters.restaurantTypes.filter(
(f) => f !== type
)
}));
} else {
setFilters((prevFilters) => ({
...prevFilters,
restaurantTypes: [...prevFilters.restaurantTypes, type]
}));
}
}}
/>
<span>{type}/span>
</label>
))}
<h3>Rating</h3>
{ratings.map((rating) => (
// same as above but for ratings
))}
</div>
);
};
So now your FilterControl
can neatly manage the state of filters
.
Now all you have to do is map over your restaurants
dataset, and only render markers whose type
and rating
are in the current filters
:
function App() {
const [filters, setFilters] = useState({
restaurantTypes,
ratings
});
return (
<MapContainer ... >
<TileLayer ... />
<FilterControl filters={filters} setFilters={setFilters} />
{restaurants.map((restaurant) => {
if (
filters.restaurantTypes.includes(restaurant.type) &&
filters.ratings.includes(restaurant.rating)
) {
return <Marker position={restaurant.coordinates} />
}
return null;
})}
</MapContainer>
);
}
Upvotes: 1