Open mister-rao opened 1 year ago
I've written a working NextJS version of react-leaflet to know what to look for:
npm install leaflet react-leaflet
In pages/index.js:
import dynamic from "next/dynamic";
import "leaflet/dist/leaflet.css";
const MapComponent = dynamic(
() => {
return import("react-leaflet").then(({ MapContainer, TileLayer }) => {
return () => (
<MapContainer
center={[51.505, -0.09]}
zoom={13}
scrollWheelZoom={true}
style={{ height: "100vh", width: "100%" }}
>
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>
);
});
},
{ ssr: false }
);
export default function Home() {
return <MapComponent />;
}
Once Reflex emits the equivalent code it should work π
@mister-rao We got it working thanks to the Reflex team in Discord! Special thanks to @Alek99 for doing the heavy lifting!
"""React-leaflet component in Reflex."""
import reflex as rx
from reflex.style import Style
class State(rx.State):
"""The app state."""
pass
class LeafletLib(rx.Component):
def _get_imports(self):
return {}
@classmethod
def create(cls, *children, **props):
custom_style = props.pop("style", {})
# Transfer style props to the custom style prop.
for key, value in props.items():
if key not in cls.get_fields():
custom_style[key] = value
# Create the component.
return super().create(
*children,
**props,
custom_style=Style(custom_style),
)
def _add_style(self, style):
self.custom_style = self.custom_style or {}
self.custom_style.update(style) # type: ignore
def _render(self):
out = super()._render()
return out.add_props(style=self.custom_style).remove_props("custom_style")
class MapContainer(LeafletLib):
library = "react-leaflet"
tag = "MapContainer"
center: rx.Var[list[float]]
zoom: rx.Var[int]
scroll_wheel_zoom: rx.Var[bool]
def _get_custom_code(self) -> str:
return """import "leaflet/dist/leaflet.css";
import dynamic from 'next/dynamic'
const MapContainer = dynamic(() => import('react-leaflet').then((mod) => mod.MapContainer), { ssr: false });
"""
class TileLayer(LeafletLib):
library = "react-leaflet"
tag = "TileLayer"
def _get_custom_code(self) -> str:
return """const TileLayer = dynamic(() => import('react-leaflet').then((mod) => mod.TileLayer), { ssr: false });"""
attribution: rx.Var[str]
url: rx.Var[str]
class UseMap(LeafletLib):
library = "react-leaflet"
tag = "useMap"
class Marker(LeafletLib):
library = "react-leaflet"
tag = "Marker"
def _get_custom_code(self) -> str:
return """const Marker = dynamic(() => import('react-leaflet').then((mod) => mod.Marker), { ssr: false });"""
position: rx.Var[list[float]]
icon: rx.Var[dict]
class Popup(LeafletLib):
library = "react-leaflet"
tag = "Popup"
def _get_custom_code(self) -> str:
return """const Popup = dynamic(() => import('react-leaflet').then((mod) => mod.Popup), { ssr: false });"""
map_container = MapContainer.create
tile_layer = TileLayer.create
use_map = UseMap.create
marker = Marker.create
popup = Popup.create
def index():
return rx.center(
map_container(
tile_layer(
attribution="© <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors",
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
),
marker(popup("Hello, world"), position=[51.505, -0.09]),
center=[51.505, -0.09],
zoom=13,
scroll_wheel_zoom=True,
height="98vh",
width="100%",
),
)
# Add state and page to the app.
app = rx.App(state=State)
app.add_page(index)
app.compile()
Note: marker-icon.png, marker-icon-2x.png and marker-shadow.png need to be in /assets for it to render correctly
Changed this to custom component request as this seems like a better fit.
related to #2855
Hi, I'd also like to find a way to do this.
I tried wrapping "React Leaflet" but I'm stuck with my limited knowledge of Reflex. Perhaps someone can help out?
In
rxconfig.py
I added:frontend_packages=["react-leaflet", "leaflet"]
toconfig
Then I add a class to my app.py:
Next, I create the
map_container
component:Similarly I add another class and create another component:
I then add both components to my index page:
Unfortunately this blows up and I get
Here's more information about React Leaflet
Thanks to iameli for helping out in DIscord
Alek99 pointed out that the undefined window error can be solved as it was done with Plotly