如何推迟将 Ajax 数据传递给子组件?

Posted

技术标签:

【中文标题】如何推迟将 Ajax 数据传递给子组件?【英文标题】:How to defer passing of Ajax data to child components? 【发布时间】:2017-10-26 01:31:45 【问题描述】:

我正在使用 Vue 2.0 使用内置的父子通信构建一个简单的待办事项应用程序。直接附加到Vue实例的父元素(new Vue(...)如下:

<!-- Tasks.vue -->
<template>
    <div>
        <create-task-form></create-task-form>

        <task-list :tasks="tasks"></task-list>

        <task-list :tasks="incompleteTasks"></task-list>

        <task-list :tasks="completeTasks"></task-list>
</template>
<script>
    import CreateTaskForm from './CreateTaskForm.vue';
    import TaskList from './TaskList.vue';

    export default 
        components:  CreateTaskForm, TaskList ,
        data()  return  tasks: [] ; ,

        created()  // Ajax call happens here...
            axios.get('/api/v1/tasks')
                .then(response => 
                    this.tasks = response.data;
                    console.log(this.tasks); // THIS IS LOGGED LAST
                );
        ,
        computed: 
            completeTasks() 
                return this.tasks.filter(task => task.complete);
            ,
            incompleteTasks() 
                return this.tasks.filter(task => task.complete);
            
        
    
</script>

这个想法是&lt;tasks&gt;&lt;/tasks&gt; 将显示一个用于创建新任务的表单,以及 3 个列表 - 所有任务、未完成任务和完成任务。每个列表都是相同的组件:

<!-- TaskList.vue -->
<template>
    <ul>
        <li v-for="task in taskList">
            <input type="checkbox" v-model="task.complete">  task.name 
        </li>
    </ul>
</template>

<script>
    export default 
        data()  return  taskList: [] ; ,
        props: ['tasks'],

        mounted() 
            this.taskList = this.tasks;
            console.log(this.tasks); // THIS IS LOGGED FIRST
        
    
</script>

问题

如您所见,我正在尝试使用动态 :tasks 属性将数据从 &lt;tasks&gt; 传递到 3 个 &lt;task-lists&gt; 中的每一个:

<task-list :tasks="tasks"></task-list>

<task-list :tasks="incompleteTasks"></task-list>

<task-list :tasks="completeTasks"></task-list>

注意,我没有使用共享(全局)状态,因为每个列表都需要不同部分数据,即使这些部分数据属于同一个存储.但问题是:tasks 被分配了一个空数组 Ajax 调用发生之前;正如我猜测的那样,道具是不可变的,因此当在父&lt;tasks&gt; 中获取数据时,子&lt;task-list&gt; 中的tasks 永远不会更新。事实上,&lt;task-list&gt; 是首先创建的(请参阅日志),然后只有在此之后才能使用 Ajax 获取数据。

问题

如何将数据从&lt;tasks&gt; 传递到我的&lt;task-list&gt;s?如何确保所有组件都引用动态更新的单一事实来源? 有没有办法用“vanilla”Vue.js 解决这个父子通信问题?还是我需要使用 Vuex 或类似的东西? 我是否正确使用属性将数据传递给孩子?还是应该在全局变量中使用共享存储?

【问题讨论】:

使用共享全局存储不是这里的问题。正如@wostex 所回答的,mounted() 只被调用一次。因此,要更新 taskList 属性,您应该使用计算属性。如果您考虑使用全局存储 vuex 将最好地解决您的目的。您可以在此处找到与您相关的示例(coligo.io/learn-vuex-by-building-notes-app) @user7814783 我在全局存储中遇到的问题(我的意思是global var declared right before the parent &lt;tasks&gt; 组件)是每个子&lt;task-list&gt; 组件都需要它自己的数据版本(所有、不完整和完整的任务)。但它仍然是相同的组件! (&lt;task-list&gt;) 所以我不知道如何从同一个商店传递不同部分的数据。 【参考方案1】:

问题出在:mounted() this.taskList = this.tasks; ...TaskList.vue 内,因为 taskList 属性仅在 mounted 事件上更新。

在 Vue 中有一个简单的解决方案:您应该将 taskList 设为依赖于 props 的 computed property,以便在父数据更改时更新您的计算属性:

props: ['tasks'],
computed: 
  taskList: function() 
    return this.tasks;
  

不要忘记从 data 块中删除 taskList

另外,我会将v-model="task.complete" 重写为@change="$emit('something', task.id)" 以通知父组件状态已更改(并收听)。否则父母永远不会知道该框已被选中。然后,您可以在父组件上侦听此事件以相应地更改任务状态。更多阅读:https://vuejs.org/v2/guide/components.html#Custom-Events

【讨论】:

非常感谢!在您关于发出事件的最后评论中,我注意到当task.completetask.name 通过v-model 进行更改时,数据的更改会反映在同级组件中,因此也会通知父级&lt;tasks&gt;。有没有办法捕获这些数据更改,所以我可以在需要时向服务器发送patch 请求? (使用事件发射,我必须将事件从一个组件传递到另一个组件,可能在一长串节点中) 您可以通过您的事件$emit('myevent', data) 传递任何数据,例如完整的对象。在您的父组件中,当您收听此事件时,您可以访问 $event 参数中的此数据:@myevent="handleEvent($event)",然后您的方法将类似于 handleEvent(event) this.newData = event - 您发送的数据。因此,您可以发送更改的task 对象并在父组件中按 id 查找任务并比较更改的内容。如果有变化 - 执行你的路径或其他。【参考方案2】:

你也可以使用vue实例的watch属性

watch:
   tasks(newVal)
        this.taskList = newVal;
      //do something
   

【讨论】:

以上是关于如何推迟将 Ajax 数据传递给子组件?的主要内容,如果未能解决你的问题,请参考以下文章

如何将数据传递给嵌套的子组件vue js?

如何将 ajax 数据传递给 React 组件?

如何将数据传递给 vue.js 中的子组件

如何将可编辑数据传递给组件?

Angular2 - 将 ASYNC 数据传递给子组件

ReactJS - 如何将“全局”数据传递给深度嵌套的子组件?