我正在尝试将我的 NextJs 项目与 Google 地图集成,然后我遇到了一个问题,当我使用地图在表单中选择一个位置然后编辑输入时,地图只是刷新并删除之前选择的 ubication ,这是我的位置选择器组件代码:
// components/LocationSelector.js
import React, { useState, useEffect } from 'react';
import { Loader } from '@googlemaps/js-api-loader';
const LocationSelector = ({ onLocationSelect }) => {
const [map, setMap] = useState(null);
const mapCenter = { lat: -3.9964339532493978, lng: -79.20091423951207 };
const mapZoom = 14;
useEffect(() => {
const loader = new Loader({
apiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API,
version: 'weekly',
});
loader.load().then(() => {
const map = new window.google.maps.Map(document.getElementById('map'), {
center: mapCenter,
zoom: mapZoom,
});
setMap(map);
var marker;
function placeMarker(location) {
if (marker) {
marker.setPosition(location);
} else {
marker = new google.maps.Marker({
position: location,
map: map,
});
}
}
map.addListener('click', (event) => {
const selectedLocation = event.latLng.toJSON();
console.log('Click en el mapa:', selectedLocation);
placeMarker(event.latLng);
onLocationSelect(selectedLocation);
});
});
}, [onLocationSelect]);
return <div id="map" style={{ height: '400px', width: '100%' }} />;
};
export default LocationSelector;
这是我的页面代码:
'use client';
import Header from "@/app/components/Header";
import { useState } from 'react';
import { Textarea } from "@nextui-org/react";
import { createEvent } from "@/app/conexion-sw/event_requests";
import LocationSelector from "@/app/components/LocationSelector";
import { set } from "mongoose";
export default function createForm() {
const [location, setLocation] = useState({ lat: 0, lng: 0 });
const [eventData, setEventData] = useState({
title: '',
date: '',
description: '',
images: [
"url_imagen_3",
"url_imagen_4"
],
category: [
"Concierto"
],
participants: [],
price: 0,
isFree: true,
capacity: 0,
address: '',
location: {
lat: 0,
lng: 0
},
});
const handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData(event.target);
const data = Object.fromEntries(formData);
data.location = location;
console.log('Datos del formulario:', data);
createEvent(data).then((res) => {
console.log("Respuesta del servidor", res);
}).catch((err) => {
console.error("Error al crear el evento", err);
});
};
const handleInputChange = (e) => {
const { name, value } = e.target;
setEventData({
...eventData,
[name]: value,
});
};
const handleLocationSelect = (selectedLocation) => {
console.log('Ubicación seleccionada frontend:', selectedLocation);
setLocation(selectedLocation);
};
const handleFileChange = (e) => {
const { name, files } = e.target;
console.log('Imágenes seleccionadas:', files);
};
return (
<div className="flex flex-col h-full bg-white-mode-background dark:bg-dark-mode-background items-center justify-center">
<Header />
<div className="h-fit w-fit rounded border bg-white-mode-bg-login border-white-mode-border text-white-mode-text dark: bg-dark-mode-bg-login dark:text-dark-mode-text dark:border-dark-mode-border items-center mt-16">
<form onSubmit={handleSubmit} className="bg-transparent p-4">
<h1 className="text-2xl font-bold mb-4 text-center">Crear Evento</h1>
<div className="mb-4">
<label htmlFor="title" className="block mb-2">
Nombre del evento:
</label>
<input
type="text"
id="title"
name="title"
className="bg-transparent p-2 rounded border w-full border-white-mode-border dark:border-dark-mode-border"
onChange={handleInputChange}
required
/>
</div>
<div className="mb-4">
<label htmlFor="date" className="block mb-2">
Fecha del evento:
</label>
<input
type="datetime-local"
id="date"
name="date"
className="bg-transparent p-2 rounded border w-full border-white-mode-border dark:border-dark-mode-border"
onChange={handleInputChange}
required
/>
</div>
<div className="mb-4">
<label htmlFor="description" className="block mb-2">
Descripción del evento:
</label>
<Textarea
id="description"
name="description"
label="Descripción"
variant="bordered"
placeholder="Ingresa la descripción del evento"
className="max-w-xs bg-transparent p-2 rounded border w-full border-white-mode-border dark:border-dark-mode-border"
onChange={handleInputChange}
required
/>
</div>
<div className="mb-4">
<label htmlFor="images" className="block mb-2">
Imágenes del evento:
</label>
<input
type="file"
/*id="images"
name="images"
*/multiple
accept="image/*"
className="bg-transparent p-2 rounded border w-full border-white-mode-border dark:border-dark-mode-border"
//onChange={handleFileChange}}
/>
</div>
<LocationSelector onLocationSelect={handleLocationSelect} />
<div className="mb-4">
<button type="submit" className="bg-blue-500 text-white p-2 rounded w-full">
Crear Evento
</button>
</div>
</form>
</div>
</div>
)
}
谢谢!
我尝试将位置分开,而不是直接将其插入到EventData变量中,因为我认为名称可能有问题,所以我仅在提交表单时更新位置数据。
我找到了解决方案,以防它对某人有帮助,问题出在组件中,特别是 onLocationSelect 函数的实例,因为更改依赖项时创建了一个新实例,所以你必须对函数进行meomize,使用 useCallBack 很容易做,这是解决方案:
// components/LocationSelector.js
import React, { useState, useEffect, useCallback } from 'react';
import { Loader } from '@googlemaps/js-api-loader';
const LocationSelector = ({ onLocationSelect }) => {
const [map, setMap] = useState(null);
const mapCenter = { lat: -3.9964339532493978, lng: -79.20091423951207 };
const mapZoom = 14;
const memoizedOnLocationSelect = useCallback(onLocationSelect, []);
useEffect(() => {
const loader = new Loader({
apiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API,
version: 'weekly',
});
loader.load().then(() => {
const map = new window.google.maps.Map(document.getElementById('map'), {
center: mapCenter,
zoom: mapZoom,
});
setMap(map);
var marker;
function placeMarker(location) {
console.log('Marcador en:', location);
if (marker) {
marker.setPosition(location);
console.log("1");
} else {
marker = new google.maps.Marker({
position: location,
map: map,
});
console.log("2");
}
}
map.addListener('click', (event) => {
const selectedLocation = event.latLng.toJSON();
console.log('Click en el mapa:', selectedLocation);
placeMarker(event.latLng);
memoizedOnLocationSelect(selectedLocation);
});
});
}, [memoizedOnLocationSelect]);
return <div id="map" style={{ height: '400px', width: '100%' }} />;
};
export default LocationSelector;