DEV Community

Cover image for React with Valtio: geolocation API with Leaflet.js
NDREAN
NDREAN

Posted on • Edited on

React with Valtio: geolocation API with Leaflet.js

Continuing to discover Valtio, we use this library to simplify the code of a React component which renders a map centred on your current location (you need to enable geolocation for the snippet above to work).

The geolocation API describes how to get the current location. Since this is an async call, you would use useEffect with dependencies. It is a bit tricky to set up. The Valtio library makes it easy: just use proxy, useSnapshot and derive for async callbacks.

The store and the async callback

We declare a store with two fields, "defaultPos" and "current", then proxy it, and then derive the "current" field from the geolocation API.

import { proxy } from 'valtio';
import { derive } from 'valtio/utils';

const defaultPos = { lat: 42.2808, lng: -83.743 };

export const gps = proxy({
  initPos: defaultPos,
  current: null,
});

derive({
  derPos: async (get) => {
    if (!navigator.geolocation) return (get(gps).initPos = defaultPos);

    navigator.geolocation.getCurrentPosition(success, fail);
    function fail(e) { return e }
    function success({ coords: { latitude, longitude } }) {
      get(gps).current = { lat: latitude, lng: longitude };
    }
  },
});
Enter fullscreen mode Exit fullscreen mode

The <App />component

In order for React to render when the position is obtained, we simply snap the desired field of the store with useSnapshot. We also need to suspend it since it's an async rendering.

import Map from './map';
import React from 'react';
import { useSnapshot } from 'valtio';

import { gps } from './geolocate';

function App() {
  const { current } = useSnapshot(gps);

  return (
    <React.Suspense fallback={<h1>Loading</h1>}>
    <div>
      {current && <Map coord={current} />}
    </div>
    </React.Suspense>

  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

The <Map /> component

We use the traditional React code as the Valtio library might not bring an obvious advantage, especially as we need to keep track of a DOM component with useRef.

import React from "react";
import "./styles.css";
import { MapContainer, TileLayer } from "react-leaflet";
export function Map({ coord: { lat, lng } }) {
  return (
    <MapContainer center={[lat, lng]} zoom={4} class="leaflet-container">
      <TileLayer
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
      />
    </MapContainer>
  );
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)