NextJS组件向页面传递数据的最佳实践:地点自动完成组件回传经纬度
实现可复用地点自动完成组件并回传地理编码的最佳实践
对于需要复用且需回传数据的组件,受控组件+回调函数是最符合React开发直觉的最佳实践。核心思路是让父组件通过props传入回调函数,子组件在完成地点选择并获取到地理编码后,调用该回调将数据传递给父组件;同时支持父组件控制输入值,保证组件的灵活性和复用性。
修改后的地点自动完成组件(PlacesAutocomplete.jsx)
import usePlacesAutocomplete, { getGeocode, getLatLng, } from "use-places-autocomplete"; import useOnclickOutside from "react-cool-onclickoutside"; // 接收父组件传入的props:onSelect(回调)、value(受控值)、onChange(值变化回调)、placeholder const PlacesAutocomplete = ({ onSelect, value, onChange, placeholder = "输入地点" }) => { const { ready, suggestions: { status, data }, setValue: setInternalValue, clearSuggestions, } = usePlacesAutocomplete({ callbackName: "YOUR_CALLBACK_NAME", requestOptions: { /* 定义搜索范围 */ }, debounce: 300, }); const ref = useOnclickOutside(() => { clearSuggestions(); }); // 处理输入变化,同步给父组件 const handleInput = (e) => { const inputValue = e.target.value; setInternalValue(inputValue); onChange?.(inputValue); }; const handleSelect = ({ description }) => async () => { setInternalValue(description, false); clearSuggestions(); onChange?.(description); // 获取经纬度并回传给父组件 try { const results = await getGeocode({ address: description }); const { lat, lng } = getLatLng(results[0]); // 调用父组件传入的回调,传递地址和经纬度 onSelect?.({ address: description, lat, lng }); } catch (err) { console.error("获取地理编码失败:", err); } }; const renderSuggestions = () => data.map((suggestion) => { const { place_id, structured_formatting: { main_text, secondary_text }, } = suggestion; return ( <li key={place_id} onClick={handleSelect(suggestion)}> <strong>{main_text}</strong> <small>{secondary_text}</small> </li> ); }); return ( <div ref={ref}> <input value={value || ""} onChange={handleInput} disabled={!ready} placeholder={placeholder} /> {status === "OK" && <ul>{renderSuggestions()}</ul>} </div> ); }; export default PlacesAutocomplete;
使用组件的页面(index.jsx)
import { useState } from "react"; import PlacesAutocomplete from "@/components/PlacesAutocomplete"; export default function Example() { // 分别管理出发地和目的地的地址、经纬度 const [origin, setOrigin] = useState({ address: "", lat: null, lng: null }); const [destination, setDestination] = useState({ address: "", lat: null, lng: null }); return ( <div className="bg-white"> <div> <h3>出发地</h3> <PlacesAutocomplete placeholder="请输入出发地" value={origin.address} onChange={(address) => setOrigin(prev => ({ ...prev, address }))} onSelect={(data) => setOrigin(data)} /> {origin.lat && <p>出发地坐标:{origin.lat}, {origin.lng}</p>} </div> <div style={{ marginTop: "20px" }}> <h3>目的地</h3> <PlacesAutocomplete placeholder="请输入目的地" value={destination.address} onChange={(address) => setDestination(prev => ({ ...prev, address }))} onSelect={(data) => setDestination(data)} /> {destination.lat && <p>目的地坐标:{destination.lat}, {destination.lng}</p>} </div> </div> ); }
方案优势
- 高复用性:组件封装了自动完成的核心逻辑,父组件只需传入不同的回调和配置,即可实现多个实例的差异化使用,无需重复初始化输入框逻辑。
- 符合单向数据流:数据由父组件管理,子组件仅负责UI渲染和触发回调,保证了React应用的数据流向清晰,便于维护。
- 灵活性强:支持受控模式(父组件控制输入值)和非受控模式(组件内部管理值),可根据需求调整;同时支持自定义占位符等配置。
内容的提问来源于stack exchange,提问作者BernardL
相关产品推荐
相关产品推荐

