Search code examples
javascriptreactjsleafletreact-leafletchakra-ui

Update tileLayer url in react-leaflet


So I got this code running to render a leaflet ok, trying to replace the url whenever the colorMode changes is the challenge here.

useEffect is triggered ok displaying the correct variable but I can't update that TileLayer in any way.

export const Map = () => {
    const { colorMode } = useColorMode();

    let state = { center: { lat: 51.505, lng: -0.09 }, zoom: 13 };

    const colorModeUrl = ['https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', 'https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png']
    useEffect(() => {
      console.log(colorMode);
    }, [colorMode]);

    return (
        <MapContainer
            center={state.center}
            zoom={state.zoom}
            style={{ height: '100%' }}>
            <TileLayer url={colorMode === 'light' ? colorModeUrl[0] : colorModeUrl[1]} />
        </MapContainer>
    )
}


Solution

  • Looking at the TileLayer documentation, the url prop is not mutable. After the initial render the component will not update if the prop is changed:

    TileLayer props

    However, you can add a ref to the layer and update the url that way

    export const Map = () => {
      const ref = useRef(null);
      const state = { center: { lat: 51.505, lng: -0.09 }, zoom: 13 };
      const { colorMode } = useColorMode();
    
      const light = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
      const dark =
     "https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png";
    
      };
    
      useEffect(() => {
        if (ref.current) {
          ref.current.setUrl(colorMode === "light" ? light : dark);
        }
      }, [colorMode]);
    
      return (
        <div>
          <MapContainer
            center={state.center}
            zoom={state.zoom}
            style={{ height: "100%" }}
          >
            <TileLayer ref={ref} url={colorMode === "light" ? light : dark} />
          </MapContainer>
        </div>
      );
    };
    

    https://codesandbox.io/s/react-leaflet-forked-1534x?file=/src/index.js:0-1158