Vue3子组件未重新创建,为什么?

sqxo8psd  于 2022-11-25  发布在  Vue.js
关注(0)|答案(1)|浏览(226)

我在这里为我问题做了一些沙盒代码:
https://codesandbox.io/s/clever-zeh-kdff1z

<template>
  <div v-if="started">
    <HelloWorld :msg="msg" @exit="exit" @remake="remake" />
  </div>
  <button v-if="!started" @click="started = !started">start</button>
</template>

<script>
import HelloWorldVue from "./components/HelloWorld.vue";
export default {
  name: "App",
  components: {
    HelloWorld: HelloWorldVue,
  },
  data() {
    return {
      started: false,
      msg: "Hello Vue 3 in CodeSandbox!",
    };
  },
  methods: {
    exit() {
      this.started = false;
    },
    remake() {
      this.msg = this.msg + 1;
      //this code should recreate our child but...
      this.exit();
      this.started = true;
      // setTimeout(() => {
      //   this.started = true;
      // });
    },
  },
};
</script>

所以!我们有两个组件父组件和子组件。这个想法很简单-我们在父组件中有一个flag变量。我们有一个v-if语句-隐藏/显示一个元素取决于flag值“false”或“true”。在我们切换flag之后-子组件应该被重新创建。这就是这个想法。很简单。
在我们的父页面中,我们有一个按钮,它将把flag变量设置为“true”,我们的子页面将被创建并显示在我们的页面上。
好了。现在我们有两个按钮在我们的孩子。一个按钮是“退出”,这是发射一个事件,使标志变量的父将设置为“假”和元素将从我们的页面消失(它将被销毁)。工程作为魅力。好。
第二个按钮“remake”。它会发出事件,这样flag变量就会被切换(关闭然后打开)。很简单。我们设置为“false”,我们设置为“true”。所以当前的孩子应该会消失,然后立即会创建一个新的。
但是现在我们面临的问题是!好的,当前的子进程仍然在这里,没有任何重新创建,它只是更新当前的一个...所以在子进程中我检查了我们的生命周期钩子-通过console.log函数创建和卸载。第二个按钮不触发它们。开始-〉退出-〉开始!=开始-〉重做。
所以有没有人能解释一下为什么会发生这种事?我想不通。
有趣的是,在我的演示中有一些异步代码注解。如果我们在async函数中将标志设置为“true”,子函数将被重新创建,我们将看到创建的钩子消息,但它看起来像拐杖。我们还可以在组件中添加一个:键,并更新它以强制重新呈现,但它看起来也像拐杖。
任何关于这个主题的解释都是很好的。

t40tm48m

t40tm48m1#

Vue会尽可能地重用元素和组件。它也只会在一个刻度上重新呈现一次。“刻度”的长度不需要你太担心,在您的例子中,this.exit()this.started = true语句在同一个时钟周期内执行。存储在this.started中的数据是最后一个价格点和当前价格点中的true,因为它不会结束语句之间的价格点,因此组件不会发生任何变化。
一般来说,你应该考虑Vue中的状态,而不是生命周期。或者换句话说:这个组件必须能够处理哪些不同的情况,以及如何在这些状态之间切换。与其确定在哪个时间点做什么,不如使用:key="keyName"实际上通常是一种拐杖,就像使用import { nextTick } from 'vue';并使用它来获得一些状态发生的节奏一样,就像使用setTimeout在当前tick之后执行一些代码一样。setTimeout的讨厌之处还在于它可以在已经被破坏的组件上执行代码。尽管有时它对动画有帮助。
根据我的经验,当人们尝试使用生命周期钩子时,他们宁愿在某个属性发生变化时发生一些事情。例如,当子组件上的一个属性id发生变化时,你希望从api加载数据来填充一些字段。要使其工作,请使用即时观察器:

watch: {
  id: {
    handler(newId, oldId) {
      this.populateFromApi(newId);
    },
    immediate: true
  }
}

现在,它将在组件创建时调用观察器,然后在您传递一个不同的id时调用它。它还将帮助您优雅地处理这样的情况,即组件是使用您期望的一个prop中的undefinednull值创建的。您不必抛出错误,而是在prop有效之前不呈现任何内容。

相关问题