如何在生命周期中处理道具更新?

时间:2019-05-25 02:12:50

标签: javascript svelte

如果父组件在生命周期内更新传递给子组件的prop的值,那么孩子如何在自己的生命周期中使用该prop的最新值?

在下面的示例中,prop值在子组件的生命周期中未定义:

App.svelte

<script>
    import { onMount } from 'svelte';
    import Nested from './Nested.svelte';

    let name;

    onMount(() => {
        name = "world";
    })
</script>

<h1>Hello <Nested name="{name}" /></h1>

Nested.svelte

<script>
    import { onMount, afterUpdate } from 'svelte';

    export let name;

    onMount(() => {
        console.log("mount name:", name);
    })

    afterUpdate(() => {
        console.log("after update name:", name);
    })
</script>

<span>{name}</span>

https://svelte.dev/repl/65ac3d9c3913408bad459e2ad2a27d8e?version=3.4.2

如果我等待tick,则生命周期中会提供最新的值,但是我不确定这是否是正确的处理方法:

App.svelte

<script>
    import { onMount } from 'svelte';
    import Nested from './Nested.svelte';

    let name;

    onMount(() => {
        name = "world";
    })
</script>

<h1>Hello <Nested name="{name}" /></h1>

Nested.svelte

<script>
    import { onMount, afterUpdate, tick } from 'svelte';

    export let name;

    onMount(async () => {
        await tick();
        console.log("mount name:", name);
    })

    afterUpdate(async () => {
        await tick();
        console.log("after update name:", name);
    })
</script>

<span>{name}</span>

https://svelte.dev/repl/9e66f312a17d41a8adf6e3e3b95c5327?version=3.4.2

2 个答案:

答案 0 :(得分:0)

在逻辑上没有人会像您一样在onMount钩子中同步设置状态 的情况,因为如果您希望它在挂载时就在那里,则应该进行设置在let name = 'world';

一种合理的情况是在onMount钩中异步地设置状态(例如,发出ajax请求并将ajax响应值设置为状态)。

如果您尝试模拟这样的异步操作

// App.svelte
onMount(() => {
    setTimeout(()=>{
        name = "world";
    },0)
})

无需使用tick(),一切正常。 afterUpdate钩子按预期收到更新的值。

https://svelte.dev/repl/9e0411ed66e34e2e8ac1937e41b2709a?version=3.4.2

答案 1 :(得分:0)

TL; DR

如果您需要在组件的onMount生命周期方法中专门运行逻辑 ,则将await tick()添加到该方法–您已经在问题中显示了-这是您唯一的选择。

如果您要这样做,则最好保持一致,并将相同的修订应用于您的afterUpdate生命周期方法。


完整答案

我怀疑您遇到的问题的一部分可能与this open issue有关,详细说明了有时afterUpdate并未被调用的方式。

在针对该问题进行修复之前(如果确实有此问题),根据您的要求,有几种方法可以解决当前的问题:

  • 按照@ jacob-goh的建议,执行name = "world"而不是setTimeout(() => name = "world")
  • 使用afterUpdate代替使用beforeUpdate
  • await tick()添加到您的生命周期方法中,就像您在问题中所显示的那样

前两个选项的缺点是,name在您孩子的onMount函数中仍然是未定义的–这是因为父母的onMount被称为 after < / em>孩子的孩子(看起来像是a relatively recent, intentional change)。因此,如果您需要在挂载孩子时专门运行逻辑,那么您会很幸运。

第二个选择的另一个缺点是,顾名思义,beforeUpdate是在 应用于DOM之前触发的。因此,如果您需要访问更新的DOM,那么您再也没有运气了。

第三个选项没有任何一个问题,但是正如您在原始问题中提到的那样,这有点...奇怪,并且一旦解决了基本问题,它可能会变得有些多余(再次,如果确实,我链接的未解决问题是相关的)。

话虽这么说,无论问题的状态如何,第三个选项都是唯一的选项,使您可以使用孩子的name方法访问更新后的onMount

添加await tick()起作用的原因是,您最终将孩子的生命周期逻辑推迟到之后应用了最新一批更改。例如,这意味着父级的onMount生命周期方法将在滴答解决之前 完成,从而允许孩子的onMount生命周期方法查看{{1 }}。