输入更改时地图组件重新加载

问题描述 投票:0回答:1

我正在尝试将我的 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变量中,因为我认为名称可能有问题,所以我仅在提交表单时更新位置数据。

google-maps google-maps-api-3 next.js13
1个回答
0
投票

我找到了解决方案,以防它对某人有帮助,问题出在组件中,特别是 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;
© www.soinside.com 2019 - 2024. All rights reserved.