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

Chr*_*tof 13 asynchronous vue.js vue-component

我有一个父/子组件设置,其中父级正在从服务器加载数据并通过道具将其传递给子级.在孩子中,我想实例化一个jQuery日历,其中包含从父级接收的一些数据.

为了在设置日历之前等待数据,我在父节目中广播了一个事件,我在子节目中设置了事件监听器.

听众正在被孩子开枪,但是如果我this.$log('theProp'),那就是未定义的.但是,如果我使用VueJs devtools检查组件,那么父/子关系就在那里,而孩子在此期间已收到道具.

支柱在儿童身上被定义为动态支柱:the-prop="theProp".由于孩子最终收到道具,我假设我的设置是正确的,但似乎有某种延迟.父母在ajax调用的return函数中设置了props,并且再次:它正在工作,只是稍有延迟.

我还尝试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()
    }
}
Run Code Online (Sandbox Code Playgroud)

J. *_*uni 23

据我所知,您不需要事件将数据从父传递给子.

所有你需要的是,在子组件中: 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;
  });
}
Run Code Online (Sandbox Code Playgroud)

现在,您不需要任何其他内容就可以将数据传递给子级.它已经在孩子身上了theProp!

你真正需要做的是在孩子身上有一些对自己财产上的数据变化作出反应的东西theProp.

在界面中:

<div v-if="theProp.id > 0">
  Loaded!
</div>
Run Code Online (Sandbox Code Playgroud)

或者在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;
  }
}
Run Code Online (Sandbox Code Playgroud)

更新1

您还可以在父级中有条件地呈现子级:

<child v-if="dataLoaded" :theProp="someData"></child>
Run Code Online (Sandbox Code Playgroud)

dataLoaded在数据可用时设置为true.

更新2

或许您的问题与变更检测警告有关

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

vm.someObject.someProperty = someValue
Run Code Online (Sandbox Code Playgroud)

......什么时候应该......

vm.$set('someObject.someProperty', someValue)
Run Code Online (Sandbox Code Playgroud)

......以及其他"警告".

更新3

在VueJS 2中,您不仅限于模板.您可以使用渲染功能并编写所需的最复杂的渲染逻辑.

更新4(关于OP的编辑2)

也许您可以删除ready并使用immediate选项,因此您的初始化位于一个位置:

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

  • 你说“现在,无论在父组件中的何处更改 someData,子组件都会做出相应的反应”,但这仅适用于“bool”、“string”和“int”类型,不适用于对象和数组。例如,如果“someData”是一个对象并且“someData.someField”发生变化,那么 Vue 将无法处理它的工作。 (4认同)

sta*_*rsp 6

这是因为Vue Parent 和 Child 生命周期钩子中的棘手行为。

通常父组件触发 created()钩子然后mount()钩子,但是当有子组件时,情况并非完全如此:父级触发 created(),然后他的子级触发created(),然后mount()并且只有在mount()加载了子级的钩子之后,父级才会mount()按照这里的解释加载他的。这就是未加载子组件中的道具的原因。

改用mounted()钩子created()

像这样https://jsfiddle.net/stanimirsp5/xnwcvL59/1/


Vol*_*iso 6

视图3

好吧,我花了大约 1.5 小时试图找出如何将 prop 从父级传递给子级:

孩子

<!-- Template -->
<template>
  <input type="hidden" name="_csrf_token" :value="csrfToken">
  <span>
    {{ csrfToken }}
  </span>
</template>

<!-- Script -->
<script>
export default {
  props: [
    "csrfToken"
  ]
}
</script>
Run Code Online (Sandbox Code Playgroud)

家长

<!-- Template -->
<template>
  <form @submit.prevent="submitTestMailForm" v-bind:action="formActionUrl" ref="form" method="POST">
...
    <CsrfTokenInputComponent :csrf-token="csrfToken"/>
...
  </form>
</template>

<!-- Script -->
<script>
...
export default {
  data(){
    return {
      ...
      csrfToken : "",
    }
  },
  methods: {
    /**
     * @description will handle submission of the form
     */
    submitTestMailForm(){
      let csrfRequestPromise = this.getCsrfToken();

      let ajaxFormData = {
        receiver     : this.emailInput,
        messageTitle : this.titleInput,
        messageBody  : this.bodyTextArea,
        _csrf_token  : this.csrfToken,
      };

      csrfRequestPromise.then( (response) => {
        let csrfTokenResponseDto = CsrfTokenResponseDto.fromAxiosResponse(response);
        this.csrfToken           = csrfTokenResponseDto.csrToken;

        this.axios({
          method : "POST",
          url    : SymfonyRoutes.SEND_TEST_MAIL,
          data   : ajaxFormData,
        }).then( (response) => {
          // handle with some popover
        })
      });
    },
    /**
     * @description will return the csrf token which is required upon submitting the form (Internal Symfony Validation Logic)
     */
    getCsrfToken(){
      ...
      return promise;
    }
  },
  components: {
    CsrfTokenInputComponent
  }
}
</script>
Run Code Online (Sandbox Code Playgroud)

长话短说

这就是您需要将道具传递给孩子的方式

    <CsrfTokenInputComponent :csrf-token="csrfToken"/>
Run Code Online (Sandbox Code Playgroud)

不是这样的

    <CsrfTokenInputComponent csrf-token="csrfToken"/>
Run Code Online (Sandbox Code Playgroud)

即使我的 IDE 一直告诉我yeap i can navigate with that prop to child- vue 无法绑定它。