How can I get geolocation parameters using Remix?

clock icon

asked 2 months ago

message

1 Answers

eye

14 Views

I'm working on a project that would benefit from being able to get a user's geolocation (latitude and longitude) from the device's GPS radio.

Naïvely adding some geolocation code to the loader for the relevant route won't work because Remix is rendering the page server-side (which is what I want), where, obviously, the geolocation code makes no sense. (Even if the server supported geolocation, I want the user's location not the server's.)

How do I implement this?

So far I've borrowed from this answer on rendering something client-side.

This kind of works, in the sense my code is executing client-side, but it still doesn't quite work. In practice, the page briefly shows "Geolocation is not supported by this browser", then the <div> disappears.

Once I can reassure myself that I can get the lat/long data and show it on the page, I assume it shouldn't be that hard to trigger something that reloads the page with the lat/long as parameters, and I can do my geolocation lookup.

I'm very much not a JavaScript expert, so forgive any neophyte mistakes or misapprehensions.

I've written this component:

const MyComponent = () => {
  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(showPosition);
  } else {
    return <div>Geolocation is not supported by this browser</div>
  }

  function showPosition(position) {
    return <div>Latitude { position.coords.latitude }, Longitude: { position.coords.longitude }</div>
  }
}

Which I'm then inserting into the page like so:

<Suspense fallback={<div>Loading</div>}>
  { MyComponent() }
</Suspense>

1 Answers

Here's a sample showing how to get client geolocation and store in server session.

https://stackblitz.com/edit/remix-run-remix-3mumcj?file=app%2Froutes%2F_index.tsx

// routes/_index.tsx

export async function loader({ request }: LoaderFunctionArgs) {
  const session = await getSession(request.headers.get('cookie'));
  return json({
    latitude: session.get('latitude'),
    longitude: session.get('longitude'),
  });
}

export async function action({ request }: ActionFunctionArgs) {
  const coords = await request.json();
  const session = await getSession(request.headers.get('cookie'));
  session.set('latitude', coords.latitude);
  session.set('longitude', coords.longitude);

  return json(
    { success: true },
    { headers: { 'set-cookie': await commitSession(session) } }
  );
}

export default function Index() {
  const { latitude, longitude } = useLoaderData<typeof loader>();
  const fetcher = useFetcher();
  useEffect(() => {
    navigator.geolocation.getCurrentPosition((position) => {
      let { latitude, longitude } = position.coords;
      fetcher.submit(
        { latitude, longitude },
        { method: 'post', encType: 'application/json' }
      );
    });
  }, [latitude, longitude]);
  return (...)
}
 

Top Questions