VueJs 子组件道具不会立即更新

新手上路,请多包涵

我有一个父/子组件设置,其中父级从服务器加载数据并通过道具将其传递给子级。在孩子中,我想用它从父母那里收到的一些数据来实例化一个 jQuery 日历。

为了在设置日历之前等待数据,我在父级中广播了一个事件,我在子级中设置了事件侦听器。

侦听器正在孩子中被解雇,但如果我 this.$log('theProp') ,它是未定义的。但是,如果我使用 VueJs devtools 检查组件,就会发现父/子关系存在并且子级同时收到了道具。

该道具在孩子上定义为动态道具 :the-prop="theProp" 。由于孩子最终确实收到了道具,我假设我的设置是正确的,但似乎有某种延迟。父级在 ajax 调用的返回函数中设置道具,并再次:它正在工作,只是看起来有一点延迟。

我还尝试在孩子的道具上注册一个 watch 监听器,这样我就可以设置日历并确保道具在那里。但是,监视侦听器会触发,但 this.$log('theProp') 仍然未定义。

如果我将数据与广播调用一起传递,例如 this.$broadcast('dataLoaded', theData) 孩子接收它就好了。但是这样做似乎是错误的,因为我基本上是在构建自己的道具处理程序。

我没有发布任何代码,因为组件相当大,并且 VueJs devtools 告诉我父/子情况正在工作。

我错过了一些信息吗?在父母中设置一个值和接收它的孩子之间是否有轻微的延迟?在孩子中等待父母数据的正确方法是什么?

通常,当您只是将数据渲染到模板中时,时间并不重要,因为数据已绑定到模板。但在这种情况下,我真的需要数据来设置日历,否则会出错。

谢谢。

编辑1: 这是一个jsfiddle: https ://jsfiddle.net/dr3djo0u/1/ 似乎确认广播后数据不可用。但是,观察者确实有效,尽管我几乎可以发誓有时 this.$log('someData') 返回 undefined 当我设置该测试用例时。

但我想我的问题可能出在其他地方,我今晚去看看,我现在没有这个项目。

编辑2: 做了更多的测试。我的问题是a)事件侦听器似乎没有立即接收数据,b)我还试图在 route.data 回调中初始化日历,如果 someData 已经存在(例如当来自父级时),但是在组件准备好之前调用了该路由回调,因此它也没有在那里工作。

我的解决方案现在是这样的:

 // works when the child route is loaded directly and parent finishes loading someData
watch: {
    someData() {
        this.initCalendar();
    }
},

// works when navigating from parent (data already loaded)
ready() {
    if (this.someData && this.someData.length) {
        this.initCalendar()
    }
}

原文由 Christof 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 264
1 个回答

据我所知,您不需要事件来将数据从父母传递给孩子。

您只需要在子组件中: props: ['theProp']

而在父组件中使用子组件时: <child :theProp="someData"></child>

现在,无论您在父组件中更改 someData ,子组件都会做出相应的反应。

你不需要事件,你不需要“观看”,你不需要“准备好”。


例如:在 AJAX 调用之后,在父级的“准备就绪”中,您加载了一些数据:

 // at the parent component

data: function () {
  return {
    someData: {}
  }
},

ready: function () {
  var vm = this;
  $.get(url, function(response) {
    vm.someData = response;
  });
}

现在, 您不需要其他任何东西来将数据传递给 child 。它已经在孩子中 theProp

你真正需要做的是,在孩子身上,有一些东西可以自己对数据变化 做出反应 theProp 属性。

在界面中:

 <div v-if="theProp.id > 0">
  Loaded!
</div>

或者在 JavaScript 代码中:

 // at the child component

computed: {
  // using a computed property based on theProp's value
  awesomeDate: function() {
    if (!this.theProp || (this.theProp.length === 0)) {
      return false;
    }
    if (!this.initialized) {
      this.initCalendar();
    }
    return this.theProp.someThing;
  }
}


更新 1

您还可以在父级中,有条件地渲染子级:

 <child v-if="dataLoaded" :theProp="someData"></child>

仅在数据可用时将 dataLoaded 设置为 true。

更新 2

或者您的问题可能与 变更检测警告 有关

也许你正在一个对象中创建一个新属性……

 vm.someObject.someProperty = someValue

……当你应该做……

 vm.$set('someObject.someProperty', someValue)

…在其他“警告”中。

更新 3

在 VueJS 2 中,您不仅限于模板。您可以使用 渲染函数 并编写您想要的最复杂的渲染逻辑。

更新 4 (关于 OP 的 编辑 2

也许你可以放弃 ready 并使用 immediate 选项,所以你的初始化在一个地方:

 watch: {
  someData: {
    handler: function (someData) {
      // check someData and eventually call
      this.initCalendar();
    },
    immediate: true
  }
}

原文由 J. Bruni 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题