组件内部具有非常奇怪行为的对象

Object with very strange behavior inside component

我有一个行为异常的对象。不知道怎么回事

我的代码:

<script>
    import { page } from '$app/stores'
    const { listingId } = $page.params
    import { db } from '../../../../firebase.config'
    import { goto } from '$app/navigation'
    import { getDoc, doc } from 'firebase/firestore'
    import { getAuth } from 'firebase/auth'
    import { scale } from 'svelte/transition'
    import LeafletMap from '$lib/LeafletMap.svelte'

    let listing = {}
    
    const auth = getAuth()

    const fetchListing = async () => {
        const docRef = doc(db, 'listings', listingId)
        const docSnap = await getDoc(docRef)

        if (docSnap.exists) {
            listing = docSnap.data()
        }

        console.log('listing', listing)
    }
    fetchListing()

    // call listing
    listing
</script>

<main in:scale>
    
    <div class="listingDetails">
        <p class="listingName">
            {listing.name} - ${listing.offer ? listing.discountedPrice : listing.regularPrice}
        </p>
        <p class="listingLocation">
            {listing.location}
        </p>
        <p class="listingType">
            Para {listing.type === 'rent' ? 'Alugar' : 'Vender'}
        </p>
        {#if listing.offer}
            <p class="discoutPrice">
                ${listing.regularPrice - listing.discountedPrice}
                de desconto
            </p>
        {/if}
        <ul class="listingDetailsList">
            <li>
                {#if listing.bedrooms > 1}
                    {listing.bedrooms} quartos
                {/if}
                {#if listing.bedrooms === 1}
                    {listing.bedrooms} quarto
                {/if}
            </li>
            <li>
                {#if listing.bathrooms > 1}
                    {listing.bathrooms} banheiros
                {/if}
                {#if listing.bathrooms === 1}
                    {listing.bathrooms} banheiro
                {/if}
            </li>
            <li>
                {#if listing.parking == true}
                    estacionamento
                {:else}
                    sem estacionamento
                {/if}
            </li>
            <li>
                {#if listing.furnished == true}
                    mobiliado
                {:else}
                    não mobiliado
                {/if}
            </li>
        </ul>
        <p class="listingLocationTitle">Localização</p>

        <LeafletMap lat={'26.2137376'} lng={'-80.2094237'} zoom={15} />

        {#if auth.currentUser?.uid == listing.user}
            <a href={`/contact/${listing.user}?listingName=${listing.name}`} class="primaryButton">
                Entre em contato com o proprietário
            </a>
        {/if}
    </div>
</main>

我的console.log('listing', listing)里面的函数fetchListing调用列表:

但是如果我尝试做同样的事情,在函数之外我会得到这个:

这很有趣,因为可以正常工作,但我需要在组件 <LeafletMap/> 中访问 listing.geolocation.latlisting.geolocation.lng。如果我把这个 {listing.geolocation.lat.toString()} 放在组件外面,我就会得到这个数字。但是如果我这样做:

<LeafletMap lat={listing.geolocation.lat.toString()} lng={'-80.2094237'} zoom={15} />

我明白了error: TypeError: Cannot read properties of undefined (reading 'lat')

我的<LeafletMap/>组件:

<script>
    import { onMount } from 'svelte'
    import { browser } from '$app/env'
    export let lat
    export let lng

    onMount(async () => {
        if (browser) {
            const leaflet = await import('leaflet')

            const map = leaflet.map('map').setView([lat, lng], 13)

            leaflet
                .tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                    attribution:
                        '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
                })
                .addTo(map)

            leaflet.marker([lat, lng]).addTo(map)
        }
    })
</script>

<main>
    <div id="map" />
</main>

<style>
    @import 'https://unpkg.com/leaflet@1.7.1/dist/leaflet.css';
    main #map {
        height: 800px;
    }
</style>

如果我这样做:<LeafletMap lat={'42.233283'} lng={'-80.2094237'} zoom={15} />我得到了完美的位置,所以,我的组件正在工作。

fetchListing 是一个异步函数,因此在呈现 LeafletMap 时可能不会设置 listing

我的建议是 add/update 设置纬度和经度后标记,如下例所示。这还允许您在运行时更新标记,并且可以轻松扩展多个标记。

<script>    
    export let lat;
    export let lng;

    let map;
    let mounted = false;
    $: if (mounted && lat && lng) updateMarkers(lat, lng);

    async function updateMarkers(latitude, longitude) {      
      const leaflet = await import('leaflet');
      leaflet.marker([latitude, longitude]).addTo(map);
      map.setView([latitude, longitude], 13);
    }

    async function createMap(container) {
      const leaflet = await import('leaflet');
      map = leaflet.map(container);
      leaflet
        .tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
          attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
        })
        .addTo(map);
      return map;
    }

    function mapAction(container) {
      createMap(container).then(function(map){
        mounted = true;
        return {
          destroy: () => {
            map.remove();
          }
        };
      });          
    }
</script>

<div style={$$props.style} use:mapAction />

<style>
  @import 'https://unpkg.com/leaflet@1.7.1/dist/leaflet.css';
  div {
      height: 800px;
  }
</style>