Resolving React Warning: Maximum Update Depth Exceeded in Google Maps Autocomplete
Recently, while implementing a Google Maps autocomplete functionality within a React component, I stumbled upon this error.
Warning: Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
The problematic code snippet looked something like this:
/// <reference types="google.maps" />
import React, { useRef, useState, useEffect } from 'react';
import { useAutocomplete, AutocompleteProps } from '@vis.gl/react-google-maps';
import { Input, InputRef } from 'antd';
/**
* https://visgl.github.io/react-google-maps/docs/api-reference/hooks/use-autocomplete
* https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform
*/
interface PlacesAutocompleteProps {
onPlaceSelect?: (place: google.maps.places.PlaceResult | null) => void;
}
const PlacesAutocomplete = ({ onPlaceSelect }:PlacesAutocompleteProps) => {
const inputRef = useRef<InputRef>(null);
const [inputValue, setInputValue] = useState<string>('');
const onPlaceChanged = (place: google.maps.places.PlaceResult | null) => {
if (place) {
setInputValue(place.formatted_address || place.name || '');
onPlaceSelect && onPlaceSelect(place);
console.log(place)
}
};
const autocompleteOptions: AutocompleteProps = {
inputField: inputRef.current?.input || null,
options: {
componentRestrictions: { country: ["us", "ca"] },
fields: ["formatted_address", "address_components", "geometry"],
types: ["address"],
},
onPlaceChanged,
};
useAutocomplete(autocompleteOptions);
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value);
};
return (
<Input ref={inputRef} value={inputValue} onChange={handleInputChange} />
);
};
export default PlacesAutocomplete;
The problem became apparent when I discovered that the error was triggered by a particular section within the component.
Identifying the Culprit
After thorough debugging, I successfully identified the root cause of the problem: the configuration options for Google Maps autocomplete were defined within the component body.
It was due to the options
object being defined inside the component and potentially causing unnecessary re-renders. To resolve this issue, we'll want to define options
outside the component to prevent re-creation of the object on each render. This way, the useEffect
won't consider options
as a dependency triggering re-renders.
Resolving the Error:
The solution was straightforward, I defined the options
as a constant
outside the component's scope, and now it no longer triggers re-renders."
// Defined outside the component
const options = {
componentRestrictions: { country: ["us", "ca"] },
fields: ["address_components", "geometry"],
types: ["address"],
};
const PlacesAutocomplete = ({ onPlaceSelect }:PlacesAutocompleteProps) => {
const inputRef = useRef<InputRef>(null);
const [inputValue, setInputValue] = useState<string>('');
const onPlaceChanged = (place: google.maps.places.PlaceResult | null) => {
if (place) {
setInputValue(place.formatted_address || place.name || '');
onPlaceSelect && onPlaceSelect(place);
console.log(place)
}
};
const autocompleteOptions: AutocompleteProps = {
inputField: inputRef.current?.input || null,
options: options, // move the declaration outside of the component
onPlaceChanged,
};
useAutocomplete(autocompleteOptions);
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value);
};
return (
<Input ref={inputRef} value={inputValue} onChange={handleInputChange} />
);
};
export default PlacesAutocomplete;