@@ -5,14 +5,15 @@ import {
55 MAPBOX_ACCESS_TOKEN ,
66 DEFAULT_VIEWPORTS ,
77} from "helpers/Constants" ;
8- import { useCallback , useReducer } from "react" ;
8+ import { useCallback , useReducer , useRef } from "react" ;
99
1010const baseUrl = `https://api.mapbox.com/geocoding/v5/mapbox.places` ;
1111
1212const initialState = {
1313 isLoading : false ,
1414 error : false ,
1515 mapboxResults : [ ] ,
16+ resultsQuery : "" ,
1617} ;
1718
1819const actionTypes = {
@@ -24,13 +25,14 @@ const actionTypes = {
2425function reducer ( state = initialState , action ) {
2526 switch ( action . type ) {
2627 case actionTypes . FETCH_REQUEST :
27- return { ...state , isLoading : true } ;
28+ return { ...state , isLoading : true , resultsQuery : action . query } ;
2829 case actionTypes . FETCH_SUCCESS :
2930 return {
3031 ...state ,
3132 error : false ,
3233 isLoading : false ,
3334 mapboxResults : action . results ,
35+ resultsQuery : action . query ,
3436 } ;
3537 case actionTypes . FETCH_FAILURE :
3638 console . error ( action . error ) ;
@@ -41,35 +43,112 @@ function reducer(state = initialState, action) {
4143}
4244
4345export function useMapboxGeocoder ( ) {
44- const [ { isLoading, error, mapboxResults } , dispatch ] = useReducer (
45- reducer ,
46- initialState
47- ) ;
46+ const [ { isLoading, error, mapboxResults, resultsQuery } , dispatch ] =
47+ useReducer ( reducer , initialState ) ;
48+ const latestQueryRef = useRef ( "" ) ;
49+
50+ const performFetch = useCallback ( async ( searchString ) => {
51+ const bbox = DEFAULT_VIEWPORTS [ TENANT_ID ] . bbox ;
52+ const mapboxUrl = `${ baseUrl } /${ searchString } .json?bbox=${ bbox } &access_token=${ MAPBOX_ACCESS_TOKEN } ` ;
53+
54+ try {
55+ const response = await axios . get ( mapboxUrl ) ;
56+ const results = response . data . features ;
57+
58+ if ( latestQueryRef . current === searchString ) {
59+ dispatch ( {
60+ type : actionTypes . FETCH_SUCCESS ,
61+ results,
62+ query : searchString ,
63+ } ) ;
64+ }
65+
66+ return results ;
67+ } catch ( error ) {
68+ if ( latestQueryRef . current === searchString ) {
69+ dispatch ( { type : actionTypes . FETCH_FAILURE , error } ) ;
70+ }
71+ return [ ] ;
72+ }
73+ } , [ ] ) ;
4874
4975 const debouncedFetch = useCallback (
5076 debounce (
5177 async ( searchString ) => {
52- const bbox = DEFAULT_VIEWPORTS [ TENANT_ID ] . bbox ;
53- const mapboxUrl = `${ baseUrl } /${ searchString } .json?bbox=${ bbox } &access_token=${ MAPBOX_ACCESS_TOKEN } ` ;
54-
55- try {
56- const response = await axios . get ( mapboxUrl ) ;
57- dispatch ( {
58- type : actionTypes . FETCH_SUCCESS ,
59- results : response . data . features ,
60- } ) ;
61- } catch ( error ) {
62- dispatch ( { type : actionTypes . FETCH_FAILURE , error } ) ;
63- }
78+ await performFetch ( searchString ) ;
6479 } ,
6580 { wait : 300 }
6681 ) ,
67- [ ]
82+ [ performFetch ]
83+ ) ;
84+
85+ const clearResults = useCallback ( ( ) => {
86+ debouncedFetch . cancel ?. ( ) ;
87+ latestQueryRef . current = "" ;
88+ dispatch ( {
89+ type : actionTypes . FETCH_SUCCESS ,
90+ results : [ ] ,
91+ query : "" ,
92+ } ) ;
93+ } , [ debouncedFetch ] ) ;
94+
95+ const searchMapboxResults = useCallback (
96+ ( searchString ) => {
97+ const normalizedSearchString = searchString . trim ( ) ;
98+ latestQueryRef . current = normalizedSearchString ;
99+
100+ if ( ! normalizedSearchString ) {
101+ clearResults ( ) ;
102+ return ;
103+ }
104+
105+ dispatch ( {
106+ type : actionTypes . FETCH_REQUEST ,
107+ query : normalizedSearchString ,
108+ } ) ;
109+ debouncedFetch ( normalizedSearchString ) ;
110+ } ,
111+ [ clearResults , debouncedFetch ]
112+ ) ;
113+
114+ const ensureMapboxResults = useCallback (
115+ async ( searchString ) => {
116+ const normalizedSearchString = searchString . trim ( ) ;
117+
118+ if ( ! normalizedSearchString ) {
119+ clearResults ( ) ;
120+ return [ ] ;
121+ }
122+
123+ if ( ! isLoading && resultsQuery === normalizedSearchString ) {
124+ return mapboxResults ;
125+ }
126+
127+ latestQueryRef . current = normalizedSearchString ;
128+ debouncedFetch . cancel ?. ( ) ;
129+ dispatch ( {
130+ type : actionTypes . FETCH_REQUEST ,
131+ query : normalizedSearchString ,
132+ } ) ;
133+
134+ return performFetch ( normalizedSearchString ) ;
135+ } ,
136+ [
137+ clearResults ,
138+ debouncedFetch ,
139+ isLoading ,
140+ mapboxResults ,
141+ performFetch ,
142+ resultsQuery ,
143+ ]
68144 ) ;
69- const fetchMapboxResults = useCallback ( ( searchString ) => {
70- dispatch ( { type : actionTypes . FETCH_REQUEST } ) ;
71- debouncedFetch ( searchString ) ;
72- } , [ ] ) ;
73145
74- return { error, isLoading, mapboxResults, fetchMapboxResults } ;
146+ return {
147+ error,
148+ isLoading,
149+ mapboxResults,
150+ resultsQuery,
151+ searchMapboxResults,
152+ ensureMapboxResults,
153+ } ;
75154}
0 commit comments