javascript - 当函数中的变量更改时,不会触发 Svelte react 性

标签 javascript svelte svelte-3

我在这里有点困惑,不幸的是我无法在 svelte 的不和谐 channel 上找到任何解决方案,所以我开始了......
我有两个类的一个相当基本的例子,让它们成为 AppComp .App创建一个 Comp实例,然后更新此实例的 value单击按钮后。
Comp 实例应将此值设置为不同的变量( inputValue ),并在更改该变量时触发 validate(inputValue)这是 react 性的。这是一个 REPL:https://svelte.dev/repl/1df2eb0e67b240e9b1449e52fb26eb14?version=3.25.1
App.svelte:

<script>
    import Comp from './Comp.svelte';
    
    let value = 'now: ' + Date.now();
    
    function clickHandler(e) {
        value = 'now ' + Date.now();
    }
</script>

<Comp
    bind:value={value}
/>
<button type="button" on:click={clickHandler}>change value</button>
比较 slim :
<script>
    import { onMount } from 'svelte';

    export let value;

    let rendered = false;
    let inputValue = '';

    $: validate(inputValue); // This doesn't execute. Why?

    function validate(val) {
        console.log('validation:', val); 
    }

    onMount(() => {
        rendered = true;
    });

    $: if (rendered) {
        updateInputValue(value);
    }

    function updateInputValue(val) {
        console.log('updateInputValue called!');
        if (!value) {
            inputValue = '';
        }
        else {
            inputValue = value;
        }
    }
</script>

<input type="text" bind:value={inputValue}>
因此,一旦更改了值:
  • 无功if (rendered) {...}条件称为
  • updateInputValue被调用并且inputValue被改变。 HTML 输入元素更新为此值。
  • validate(inputValue)从未对这种变化使用react - 为什么?

  • 如果我省略对 updateInputValue 的额外调用 react 中的函数if (rendered)条件和放置updateInputValue函数体的代码直接到条件,然后validate(inputValue)被正确触发,即:
    // works like this  
    $: if (rendered) {
        if (!value) {
            inputValue = '';
        }
        else {
            inputValue = value;
        }
    }
    
    那么为什么在函数中更新它不起作用呢?

    最佳答案

    @johannchopin 的 answer揭示了这个问题。

    您可以阅读my blogpost for slightly in-depth explanation of how reactive declaration works ,这里是 tl;博士:

  • 响应式声明被执行 批量 .
    svelte 批处理所有更改以在下一个更新周期中更新它们,并且在更新 DOM 之前,它将执行响应式声明以更新响应式变量。
  • 响应式声明被执行 订购 他们的依赖。
    响应式(Reactive)声明是批量执行的,每个声明执行一次。一些声明相互依赖,例如:
    let count = 0;
    $: double = count * 2;
    $: quadruple = double * 2;
    
    在这种情况下,quadruple取决于 double .所以不管你的 react 声明的顺序如何,$: double = count * 2;之前 $: quadruple = double * 2或者反过来,前者应该是和 将是 在后者之前执行。
    slim 将排序 依赖顺序中的声明。
    在彼此没有依赖关系的情况下:
    $: validate(inputValue);
    $: if (rendered) updateInputValue(value);
    
    第一条语句取决于 validateinputValue , 第二条语句取决于 rendered , updateInputValuevalue ,声明保持原样。

  • 现在,了解了响应式(Reactive)声明的这两种行为,让我们来看看你的 REPL .
    当你改变 inputValue , renderedvalue , Svelte 将批量更改,并开始新的更新周期。
    在更新 DOM 之前,Svelte 将一次性执行所有的响应式(Reactive)声明。
    因为 validate(inputValue); 之间没有依赖关系和 if (rendered) updateInputValue(value);语句,(如前所述),它们将按顺序执行。
    如果您更改 renderedvalue只有,第一条语句( validate(inputValue) )不会被执行,同样,如果你改变 inputValue第二条语句 ( if (rendered) updateInputValue(value) ) 不会被执行。
    现在,在 updateInputValue您更改 inputValue 的值,但因为我们已经处于更新周期,我们不会开始一个新的。
    这通常不是问题,因为如果我们按照依赖顺序对响应式声明进行排序,更新所依赖变量的语句将在依赖变量的语句之前执行。

    因此,知道出了什么问题,您可以寻求一些“解决方案”。
  • 手动重新排序响应式(Reactive)声明语句,尤其是在执行顺序存在隐式依赖时。

  • 请参阅此 REPL 中订购响应式(Reactive)声明的区别
    因此,将您的 REPL 更改为:
    $: if (rendered) {
      updateInputValue(value);
    }
    $: validate(inputValue);
    
    See REPL
  • 在响应式声明中显式定义依赖关系

  • $: validate(inputValue);
    
    $: if (rendered) {
        inputValue = updateInputValue(value);
    }
        
    function updateInputValue(val) {
        console.log('updateInputValue called!');
        if (!value) {
            return '';
        }
        else {
            return value;
        }
    }
    
    See REPL

    关于javascript - 当函数中的变量更改时,不会触发 Svelte react 性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63934543/

    相关文章:

    javascript - 如何在 JavaScript 中创建对象的唯一实例?

    javascript - 是的,数组验证 - 仅当数组长度大于 1 时才需要值

    纤细的组件不刷新

    javascript - 每个转换而不是每个组件定义的 Svelte 转换

    tailwind-css - 如何在 SvelteKit 中使用 Tailwind 背景图片

    javascript - 如何有效地序列化 64 位 float 以便字节数组保留自然数字顺序?

    javascript - Highcharts 甘特图工具提示鼠标悬停跟踪问题

    svelte - 使用 Sveltekit 和 Tailwind CSS

    svelte - 从 _layout 中排除页面