【问题标题】:How does Svelte reactivity work inside functions?Svelte 反应性如何在函数内部工作?
【发布时间】:2020-01-18 02:57:38
【问题描述】:

我在 Svelte 的反应性方面存在一些严重问题。我已经隔离了我认为至少是我的主要问题之一。将变量绑定到复选框时,在函数内部而不是外部设置变量时反应性似乎中断。这是预期的行为吗?在那种情况下为什么?预期的工作流程是什么?

示例代码,一个 Svelte 组件:

<script>
    let foo = true;

    // This assignment works both on the plain text view (Foo: true/false)
    // and on the checkbox
    // setInterval(() => foo = !foo, 500)

    // This assignment works only on the plain text view (Foo: true/false)
    // but not for the checkbox
    function action() {
        foo = !foo;
    }
</script>

Foo: { foo }<br />
Checkbox: <input type="checkbox" bind:checked={ foo } on:click|preventDefault={ action } />

Svelte REPL 来看看这个问题的实际效果:https://svelte.dev/repl/73de7d705ab3442786710cd88ea3f625?version=3.12.1

【问题讨论】:

    标签: javascript svelte


    【解决方案1】:

    最好的解决方案要简单得多,因为双向绑定本身就可以满足您的所有需求。所以,这样做:

    <script>
      let foo = true;
    </script>
    
    Foo: { foo }<br />
    Checkbox: <input type="checkbox" bind:checked={ foo } />
    

    我知道这个问题已经存在两年了,但我认为它需要更好地结束。

    【讨论】:

      【解决方案2】:

      我建议不要使用 preventDefault 取消事件,因为它会停止复选框的默认行为。

      因此reactivitybroken。如果您将 foo 的重新分配包装在 setTimeout 中,您只会欺骗事件循环并且不会阻止默认值。

      因此,如果您想停止事件的传播,请根据 Filip 的建议使用 preventDefault。

          <script>
              let foo = true;
      
              // This assignment works both on the plain text view (Foo: true/false)
              // and on the checkbox
              // setInterval(() => foo = !foo, 500)
      
              // This assignment works only on the plain text view (Foo: true/false)
              // but not for the checkbox
              async function action(e) {
                      e.preventDefault();
                      setTimeout(() => {foo =! foo});
      
              }
          </script>
      
          Foo: { foo }<br />
          Checkbox: <input type="checkbox" bind:checked={ foo } on:click={ action } />
      

      【讨论】:

      • preventDefault 是必需的,因为例如在函数中完成异步操作之前状态不应更改。很遗憾,它并没有解决我的问题,但谢谢。 :)
      • 我已对您的建议进行了答复。以便在异步操作中处理状态更改并阻止默认值
      • 嗯,我尝试在 REPL 中移动 preventDefault 但也无法使其正常工作? svelte.dev/repl/f6fefe4f1656429d980d964c1ff25b53?version=3.12.1 (不同之处在于我在操作中添加了 e:所以 preventDefault() 实际运行)
      【解决方案3】:

      似乎您的问题是由bind: 选项引起的。这样做会导致 foo 被更新两次:一次用于“动作”,一次是在绑定启动时在幕后。

      只需删除 bind: 即可

      <script>
          let foo = true;
      
          // This assignment works both on the plain text view (Foo: true/false)
          // and on the checkbox
          // setInterval(() => foo = !foo, 500)
      
          // This assignment works only on the plain text view (Foo: true/false)
          // but not for the checkbox
          function action() {
              setTimeout(() => foo = !foo, 1000);
          }
      </script>
      
      Foo: { foo }<br />
      Checkbox: <input type="checkbox" checked={ foo } on:click|preventDefault={ action } />
      

      这是有道理的,因为您确实希望将选中状态双向绑定到 foo。您只希望复选框反映 foo 的值。

      【讨论】:

      • 代码示例有效,但诀窍在于 setTimeout()。即使我添加了 bind: back,它也可以工作,只要 foo 声明在该超时内而不是直接在函数第一范围内。
      【解决方案4】:

      如果您将变量声明包装在 setTimeout 中而没有任何时间限制(使其默认为 0 并因此尽快运行),您的代码将起作用。

      function action() {
          setTimeout(() => {
              foo = !foo;
          });
      }
      

      我希望我能解释为什么会这样,但我不能......

      【讨论】:

        猜你喜欢
        • 2019-12-05
        • 2020-01-18
        • 2021-10-23
        • 1970-01-01
        • 2015-11-25
        • 2019-02-01
        • 2020-11-29
        • 2015-09-18
        • 2019-10-08
        相关资源
        最近更新 更多