如何从 mounted() 和 created() 挂钩中的 AJAX 调用中获取 Vue 道具和数据

How to get Vue props and data fetched from within an AJAX call in the mounted() and created() hooks

我只是尝试将使用内置 fetch() 方法从 AJAX 调用中获取的数据设置到我的 Vue 组件的数据变量 courts 中(我' m 使用 Vue2)。

我知道当您进入 fetch() 方法时,关键字 this 的上下文可能会发生变化。但是,如果我将变量 courts 作为道具绑定到我的子组件 ,它会呈现到 HTML,但我仍然无法访问道具,例如,created()mounted() 生命周期挂钩。

我已经读过 ,它指出了关键字 this 的问题。

由于 JavaScript 的异步工作流程,我还检查是否使用我使用的 setTimeout() 方法获取数据,但不是 在我的子组件中作为道具

我从 Webpack 加载了 Babel,我试图用 async await 函数来解决它,但没有成功。

App.vue(父组件)

<template>
    <div class="container">
        <court-map v-bind:items="courts"></court-map>
        <navbar v-bind:items="courts"></navbar>
    </div>
</template>

<script>
    import CourtMap from './components/CourtMap.vue';
    import Navbar from './components/Navbar.vue';

    export default {
        components: {
            'navbar': Navbar,
            'court-map': CourtMap
        },
        data() {
            return {
                courts: [],
            }
        },
        created() {
            this.getCourts();
        },
        methods: {
            getCourts() {
                let _self = this;
                fetch('/api/courts', {
                    method: 'GET',
                    headers: {
                        'Accept': 'application/json',
                        'Content-type': 'application/json'
                    }
                })
                .then(response => response.json())
                .then(data => {
                    _self.courts = data; // With alias
                    this.courts = data;
                    console.log(_self.courts); // Shows my data
                })
                    .catch(error => console.error(error));

                console.log(_self.courts); // No longer shows my data
                setTimeout(function() {
                    console.log(_self.courts); // Shows my data
                    console.log(this.courts); // Undefined
                }, 3000);
            }
        }
    }
</script>

我也使用 this.$props.items 访问我的道具,但它给了我一个空数组。

CourtMap.vue(子组件)

编辑:抱歉,我忘记在变量索引中使用 this

<template>
    <div class="map-viewer">
        <div class="esri-widget">
            <camera-info v-bind:camera="camera"></camera-info>
        </div>
        <div>{{ items }}</div> // Renders the prop with the right data
        <div id="viewMap"></div>
    </div>
</template>

<script>
    import { loadModules } from 'esri-loader';

    export default {
        components: {
            'camera-info': CameraInfo
        },
        props: {
            items: {
                type: Array,
                required: true
            },
        },
        data() {
            return {
                firstIndex: 0,
                camera: {
                    position: {
                        longitude: this.items[this.firstIndex].longitude, // Return this is not defined
                        latitude: this.items[this.firstIndex].latitude // Return this is not defined
                    },
                    tilt: 0,
                    heading: 0
                },
            }
        },
        created() {
        },
        methods: {
            createMap() {
               // Some function here
            }
        },
        mounted() {
            console.log(this.items); // Doesn't show the data
            setTimeout(function() {
                console.log(this.items); // Doesn't show the data too
            }, 3000);
            this.createMap();
        },
    }
</script>

Index.js(我启动 Vue 应用程序的地方)


import Vue from 'vue';
import App from './App.vue';

new Vue({
    render: h => h(App)
}).$mount('#app');

我想这是新手必须经历的事情,但出于这个原因,我想知道每次我想在 Vue 中访问一个获取的数据时我必须遵循哪种模式。我现在不知道如何进行。

预先感谢您花时间阅读本文。

让我们弄清楚一些事情。

this 不只是随机变化。当您输入新功能时,它会发生变化。使用 self 这样的别名在历史上是避免此问题的一种方法,但在您的情况下,您使用的是箭头函数。箭头函数不会更改周围范围的 this 值。

现在让我们看看为什么这不起作用:

mounted () {
    console.log(this.items); // Doesn't show the data
    setTimeout(function() {
        console.log(this.items); // Doesn't show the data too
    }, 3000);

它第一次尝试访问 this.items 太早了。异步 fetch 尚未完成。

第二次,在 setTimeout 中,我们得到了一个新函数,因此 this 值发生了变化。使用箭头函数应该显示正确的数据:

setTimeout(() => {
    console.log(this.items);
}, 3000);

当然,假设数据在 3 秒内加载。

当然,计时器不是处理此问题的正确方法。

最简单的选择是在数据可用之前避免创建子组件:

<court-map v-if="courts.length" :items="courts"></court-map>

v-if 将阻止创建组件,直到数组中有条目为止。这样做可以确保 createdmounted 挂钩不会 运行 直到 courts 准备好作为 items.[=39= 传递]

也许空数组不是此处初始值的最佳选择,因为除了服务器返回的空数组外很难分辨。相反,如果我们最初使用 null 值会变得更简单。

data() {
    return {
        courts: null
    }
},

与:

<court-map v-if="courts" :items="courts"></court-map>

其他使用 courts 的代码可能需要相应调整。

或者,如果您不想使用 v-if 来延迟子项的创建,那么您可以在子项中使用 watch 来等待 items 更改。然后您可以触发任何需要发生的操作。

关于此行为何不起作用的进一步说明:

longitude: this.items[firstIndex].longitude

所以第一个问题是 this.items 还没有加载(如上所述)。第二个问题是 firstIndex 未定义。 firstIndex: 0 上面几行是无关紧要的。 this.items[firstIndex] 正在尝试使用名为 firstIndex 的局部变量,但该变量不存在。

在不了解更多的情况下很难说,但 position 可能更好地实现为计算 属性。