如何将服务器端外部API数据传递给客户端Mapbox组件?
解决方案
直接在客户端组件mapbox.tsx里调用服务端的Build_And_Fetch函数会触发CORS错误——因为客户端组件在浏览器环境中运行,直接请求外部API会受浏览器跨域策略限制;而Build_And_Fetch原本是在服务端执行的,服务端请求外部API不受浏览器CORS约束。
下面是两种可行的解决方法:
方法一:服务端预取数据,通过Props传递给客户端组件
在服务端组件(比如页面文件page.tsx)中调用Build_And_Fetch获取数据,再将数据作为props传给客户端组件MapboxMap:
// app/page.tsx(服务端组件,无需加"use client") import MapboxMap from './mapbox'; import { Build_And_Fetch } from './data'; export default async function Home() { const weatherData = await Build_And_Fetch(); return ( <div style={{ width: '100vw', height: '100vh' }}> <MapboxMap jsondata={weatherData} /> </div> ); }
修改mapbox.tsx的props定义,确保正确接收数据:
// mapbox.tsx "use client" import * as React from "react"; import mapboxgl, { Map } from "mapbox-gl"; import "mapbox-gl/dist/mapbox-gl.css"; // 替换原props定义,建议用更具体的类型代替any const MapboxMap = ({ jsondata }: { jsondata?: any }) => { const [map, setMap] = React.useState<mapboxgl.Map>(); const mapNode = React.useRef(null); mapboxgl.accessToken = "pk.eyJ1IjoiY2djdHNjaWVuY2VjZW50ZXIiLCJhIjoiY2xpM2dld3AzMGJkbTNlcGZ2aHowajZncCJ9.vFc7nroP3Pa0Cg7KAxvZjw"; React.useEffect(() => { const node = mapNode.current; if(typeof window === "undefined" || node === null) return; const mapboxMap = new mapboxgl.Map({ container: node, style: "mapbox://styles/mapbox/light-v11", center: [-72,41], zoom:0.6 }); setMap(mapboxMap); mapboxMap.on('load', () => { if (!jsondata) return; // 使用传入的jsondata作为数据源 mapboxMap.addSource("weather-data",{ "type":"geojson", "data": jsondata }); // 可在此添加图层渲染逻辑 }); return () => {mapboxMap.remove()}; }, [jsondata]); // 添加jsondata作为依赖,数据更新时重新处理地图 return <div ref={mapNode} style={{width:"100%",height:"100%"}}/>; } export default MapboxMap
方法二:创建内部API路由,客户端请求该路由获取数据
在app/api/weather/route.ts创建API路由,在路由内部调用Build_And_Fetch:
// app/api/weather/route.ts import { Build_And_Fetch } from '@/app/data'; import { NextResponse } from 'next/server'; export async function GET() { try { const data = await Build_And_Fetch(); return NextResponse.json(data); } catch (error) { return NextResponse.json({ error: 'Failed to fetch weather data' }, { status: 500 }); } }
然后在mapbox.tsx中请求这个内部API:
// mapbox.tsx "use client" import * as React from "react"; import mapboxgl, { Map } from "mapbox-gl"; import "mapbox-gl/dist/mapbox-gl.css"; const MapboxMap = () => { const [map, setMap] = React.useState<mapboxgl.Map>(); const [weatherData, setWeatherData] = React.useState<any>(null); const mapNode = React.useRef(null); mapboxgl.accessToken = "pk.eyJ1IjoiY2djdHNjaWVuY2VjZW50ZXIiLCJhIjoiY2xpM2dld3AzMGJkbTNlcGZ2aHowajZncCJ9.vFc7nroP3Pa0Cg7KAxvZjw"; // 获取数据 React.useEffect(() => { const fetchData = async () => { const res = await fetch('/api/weather'); const data = await res.json(); setWeatherData(data); }; fetchData(); }, []); React.useEffect(() => { const node = mapNode.current; if(typeof window === "undefined" || node === null || !weatherData) return; const mapboxMap = new mapboxgl.Map({ container: node, style: "mapbox://styles/mapbox/light-v11", center: [-72,41], zoom:0.6 }); setMap(mapboxMap); mapboxMap.on('load', () => { mapboxMap.addSource("weather-data",{ "type":"geojson", "data": weatherData }); // 添加图层渲染逻辑 }); return () => {mapboxMap.remove()}; }, [weatherData]); return <div ref={mapNode} style={{width:"100%",height:"100%"}}/>; } export default MapboxMap
两种方法对比:
- 方法一适合需要预渲染数据的场景,页面加载时已获取数据,SEO友好。
- 方法二更适合动态刷新数据的场景,比如用户触发操作后重新获取数据。
内容的提问来源于stack exchange,提问作者Chris Gergler
相关产品推荐
相关产品推荐

