Advanced - Current Location Search on Page Load | Yext Hitchhikers Platform
What You’ll Learn
In this section, you will:
- Add logic to StoreLocator in order to run a current location search on page load
Overview
So far in this module, you have had to manually run a search on “New York City, New York, United States” in order to see changes to your locator. In this unit, you will add logic to your component in order to run a search based on the current location of the user when the page loads:
1. Add Current Location Search Logic to a useEffect hook
In StoreLocator.tsx
, update your imports:
// src/components/StoreLocator.tsx
import {
MapboxMap,
FilterSearch,
OnSelectParams,
VerticalResults,
getUserLocation, // New
} from "@yext/search-ui-react";
import { useEffect, useState } from "react"; // New
import { BiLoaderAlt } from "react-icons/bi"; // New
import {
Matcher,
SelectableStaticFilter,
useSearchActions,
useSearchState // New
} from "@yext/search-headless-react";
// Mapbox CSS bundle
import "mapbox-gl/dist/mapbox-gl.css";
import LocationCard from "./LocationCard";
import MapPin from "./MapPin";
// component code...
Then, add some new logic to your component:
// src/components/StoreLocator.tsx
// imports...
type InitialSearchState = "not started" | "started" | "complete";
const StoreLocator = (): JSX.Element => {
const searchActions = useSearchActions();
// new code starts here...
const [initialSearchState, setInitialSearchState] =
useState<InitialSearchState>("not started");
const searchLoading = useSearchState((state) => state.searchStatus.isLoading);
useEffect(() => {
getUserLocation()
.then((location) => {
searchActions.setStaticFilters([
{
selected: true,
displayName: "Current Location",
filter: {
kind: "fieldValue",
fieldId: "builtin.location",
value: {
lat: location.coords.latitude,
lng: location.coords.longitude,
radius: 40233.6, // equivalent to 25 miles
},
matcher: Matcher.Near,
},
},
]);
})
.catch(() => {
searchActions.setStaticFilters([
{
selected: true,
displayName: "New York City, New York, NY",
filter: {
kind: "fieldValue",
fieldId: "builtin.location",
value: {
lat: 40.7128,
lng: -74.006,
radius: 40233.6, // equivalent to 25 miles
},
matcher: Matcher.Near,
},
},
]);
})
.then(() => {
searchActions.executeVerticalQuery();
setInitialSearchState("started");
});
}, []);
useEffect(() => {
if (!searchLoading && initialSearchState === "started") {
setInitialSearchState("complete");
}
}, [searchLoading]);
// ...and ends here
const handleFilterSelect = (params: OnSelectParams) => {
const locationFilter: SelectableStaticFilter = {
displayName: params.newDisplayName,
selected: true,
filter: {
kind: "fieldValue",
fieldId: params.newFilter.fieldId,
value: params.newFilter.value,
matcher: Matcher.Equals,
},
};
searchActions.setStaticFilters([locationFilter]);
searchActions.executeVerticalQuery();
};
return (
<>
{/* new JSX starts here... */}
<div className="relative flex h-[calc(100vh-210px)] border ">
{initialSearchState !== "complete" && (
<div className="absolute z-20 flex h-full w-full items-center justify-center bg-white opacity-70">
<BiLoaderAlt className="animate-spin " size={64} />
</div>
)}
{/* ...and ends here */}
<div className="w-1/3 flex flex-col">
<FilterSearch
onSelect={handleFilterSelect}
placeholder="Find Locations Near You"
searchFields={[
{
entityType: "location",
fieldApiName: "builtin.location",
},
]}
/>
<VerticalResults
customCssClasses={{ verticalResultsContainer: "overflow-y-auto" }}
CardComponent={LocationCard}
/>
</div>
<div className="w-2/3">
<MapboxMap
mapboxAccessToken={YEXT_PUBLIC_MAPBOX_API_KEY || ""}
PinComponent={MapPin}
/>
</div>
</div>
</>
);
};
You added quite a bit of code so let’s review:
- You’ve added the
InitialSearchState
type which is used as the type forinitialSearchState
. - The first
useEffect
hook will run the first time theStoreLocator
component renders.getUserLocation
will prompt the user to grant the site access to their location. If they grant location access, a location filter for the user’s location called “Current Location” will be set in the search state. If the user denies access, a filter will be set on the coordinates in New York City. - Once location access has been granted or denied, the
then
block will execute a vertical query and setinitialSearchState
to “started”. - The second
useEffect
hook will set initial search state to “complete” once the initial search has completed. You will use this state variable in your JSX. - While the component is waiting on the user to grant or deny usage of their location to the browser, you will use the
initialSearchState
flag to conditionally render a spinning loader icon. When the JSX is updated, a panel that contains a spinning icon over the results and map will appear.
If your site isn’t already running, start it back up with npm run dev
and go the locator page. The browser should prompt you on whether or not you want to grant location access.
Note
An alternative way of implementing current location search would be to run an initial search on set coordinates (e.g. 40.7128, -74.006) when the component renders without waiting for user permission. If the user grants permission, you could then run a second search after their location is provided.
unit Quiz
+20 points
Daily Quiz Streak: 0
Quiz Accuracy Streak: 0
Question 1 of 1
Which hook do we use to run a current location search on page load?
You're out of this world! 🌎
You've already completed this quiz, so you can't earn more points.You completed this quiz in 1 attempt and earned 0 points! Feel free to review your answers and move on when you're ready.
1st attempt
0 incorrect
Sign up for Hitchhikers to start earning points!
If you're already a Hitchhiker, log in to access this content.
Feedback
<% elem.innerText %>