Shadcn Accordion内Google Maps Autocomplete无法给出地点建议的解决方法
解决Google Places Autocomplete在Shadcn Accordion内无地点建议的问题
问题根源
Shadcn的AccordionContent在折叠状态下会将内部元素设为display: none,而Google Places Autocomplete初始化时依赖输入框的可见状态。组件挂载时Accordion默认折叠,输入框不可见,导致Autocomplete无法完成完整的初始化绑定,自然无法触发地点建议。而开发模式热更新时Accordion已展开,输入框处于可见状态,所以初始化能正常生效。
解决方案
方法1:监听Accordion展开状态动态初始化
通过跟踪Accordion的展开状态,在展开后初始化Autocomplete,折叠时销毁旧实例避免内存泄漏:
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "../components/ui/accordion" import { Input } from "../components/ui/input"; import { useEffect, useRef, useState } from "react"; export default function AccountSettings() { const autoCompleteRef = useRef<HTMLInputElement>(null); const autoCompleteInstanceRef = useRef<google.maps.places.Autocomplete | null>(null); const [isOpen, setIsOpen] = useState(false); useEffect(() => { // 折叠时清理旧实例 if (!isOpen && autoCompleteInstanceRef.current) { google.maps.event.clearInstanceListeners(autoCompleteInstanceRef.current); autoCompleteInstanceRef.current = null; return; } // 展开时初始化新实例 if (isOpen && autoCompleteRef.current && !autoCompleteInstanceRef.current) { autoCompleteInstanceRef.current = new google.maps.places.Autocomplete(autoCompleteRef.current); } }, [isOpen]); return ( <div> <Accordion type="single" collapsible onValueChange={(value) => setIsOpen(value === "item-1")} > <AccordionItem value="item-1"> <AccordionTrigger> <span>Location Accordion</span> </AccordionTrigger> <AccordionContent> <Input ref={autoCompleteRef} placeholder="Choose a location" /> </AccordionContent> </AccordionItem> </Accordion> </div> ) }
方法2:用IntersectionObserver监听输入框可见性
如果不想依赖Accordion的状态,可以通过IntersectionObserver监听输入框是否进入可视区域,在可见时初始化:
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "../components/ui/accordion" import { Input } from "../components/ui/input"; import { useEffect, useRef } from "react"; export default function AccountSettings() { const autoCompleteRef = useRef<HTMLInputElement>(null); const autoCompleteInstanceRef = useRef<google.maps.places.Autocomplete | null>(null); useEffect(() => { if (!autoCompleteRef.current) return; const observer = new IntersectionObserver((entries) => { const [entry] = entries; if (entry.isIntersecting && !autoCompleteInstanceRef.current) { // 元素可见时初始化Autocomplete autoCompleteInstanceRef.current = new google.maps.places.Autocomplete(autoCompleteRef.current!); } else if (!entry.isIntersecting && autoCompleteInstanceRef.current) { // 元素不可见时销毁实例 google.maps.event.clearInstanceListeners(autoCompleteInstanceRef.current); autoCompleteInstanceRef.current = null; } }, { threshold: 0.1 }); observer.observe(autoCompleteRef.current); return () => { observer.disconnect(); if (autoCompleteInstanceRef.current) { google.maps.event.clearInstanceListeners(autoCompleteInstanceRef.current); } }; }, []); return ( <div> <Accordion type="single" collapsible> <AccordionItem value="item-1"> <AccordionTrigger> <span>Location Accordion</span> </AccordionTrigger> <AccordionContent> <Input ref={autoCompleteRef} placeholder="Choose a location" /> </AccordionContent> </AccordionItem> </Accordion> </div> ) }
关键注意事项
- 必须清理旧实例:每次折叠或组件卸载时,调用
google.maps.event.clearInstanceListeners销毁Autocomplete实例,避免内存泄漏和事件冲突。 - 避免在组件挂载时直接初始化:此时输入框处于不可见状态,Google API无法完成完整的事件绑定和建议面板初始化。
内容的提问来源于stack exchange,提问作者Jasperan
相关产品推荐
相关产品推荐

