1. 地图选点组件:从一个业务需求聊起
干 React 这行,你早晚会接到一个需求:地图上选个点,拿到经纬度,再把地址回填给表单。这事听起来简单,但真做起来,从组件封装到 Hook 管理,再到回显、搜索、埋点,一线坑踩下来真的不少。
这篇文章我就用“React + 高德地图”做一套完整的地图选点组件,把从 0 到 1 的拆解思路、代码结构、参数选择、问题排查全部捋一遍。无论你是刚学 React 的初级前端,还是被这类功能反复拷打的资深开发,都能从中找到可以直接“抄作业”的落地方案。
高德地图在国内的加载速度、中文地址体系和 POI 搜索精度上是有明显优势的,而且 JS API 对 React 的适配相对友好,不用自己捏造一堆类型和事件绑定。如果用百度地图或者 Mapbox GL,思路大同小异,只是 API 名称和配置入口不同,所以这篇文章以高德为主线,最后我会补一套通用的组件抽象思路,帮你以后迁移到其他地图 SDK 时少走弯路。
2. 组件化设计:为什么不能把地图代码直接怼进业务页面
2.1 直接写在页面里会踩到什么坑
很多新手拿到这个需求,第一反应是去页面里 new AMap.Map,然后把 marker 丢上去,click 事件里拿一下经纬度。一顿操作猛如虎,页面效果也出来了,但问题攒了一堆:
地图实例和 React 组件生命周期没有绑定关系,切换路由后地图容器已经被 React 卸载了,但 AMap 实例可能还在,轻则内存泄漏,重则控制台直接报错。
重复进入页面时,地图会重新加载,没有实例缓存和复用机制,白屏时间长,用户体感极差。
地址逆解析、POI 搜索的数据流全靠 eventHandler 往全局变量里塞,组件卸载后这些回调还在飞,状态更新指向已卸载的组件,React 18 + StrictMode 下这个问题尤其明显。
换句话说,“能跑”和“能交付”之间差了一个工程化组件设计的距离。地图选点这个需求本质上不是一个“页面”,而是一个可复用的功能单元,它需要独立的渲染控制、状态隔离、实例管理,这些东西全部塞进业务页面会让耦合度高到爆炸。
2.2 组件的边界该怎么划
我习惯把地图选点拆成三个层次:
- 容器层:负责地图容器的 div 挂载、宽高控制、实例初始化。
- 逻辑层:封装选点流程、逆地理编码、搜索功能、事件绑定。
- 数据层:向父组件暴露 onChange,把选中的经纬度和地址文本回传。
对应的 React 实现上,就用一个 MapPicker 组件,配合一个 useMapPicker Hook。组件管“地图长什么样”,Hook 管“选点逻辑怎么跑”,父组件只负责接收数据。
这种划分方式是做 React 业务组件的一个通用原则,不只是地图,你再去看别的复杂组件,日期选择、文件上传、富文本编辑器,核心思路都是一样的:视图归视图,逻辑归逻辑,数据归数据。三件事搅在一起,后面的每一次迭代都会变成噩梦。
2.3 为什么选择高德的 JS API 2.0
高德地图的 JS API 2.0 和 1.4.x 差别非常大。2.0 开始支持按需加载,你不再需要手动在 index.html 里写死一个