【问题标题】:Svelte input binding breaks when a reactive value is a reference type?当反应值是引用类型时,Svelte 输入绑定会中断?
【发布时间】:2020-07-04 14:58:48
【问题描述】:

(我是 Svelte 的新手,所以我很可能在这里做错了)

更新:我添加了第二个稍微不同的 REPL,它可以更好地证明问题。试试这个:https://svelte.dev/repl/ad7a65894f8440ad9081102946472544?version=3.20.1


我在尝试将文本输入绑定到反应值时遇到了问题。

我正在努力用文字来描述这个问题,所以希望在随附的 REPL 中对该问题进行简化的演示会更有意义。

https://svelte.dev/repl/6c8068ed4cc048919f71d87f9d020696?version=3.20.1

该演示在一个页面上包含两个自定义<Selector> 组件。


第一个组件被传递了两个字符串值(“one”和“two”):

<Selector valueOne="one" valueTwo="two"/>

单击输入字段旁边的按钮将selectedValue 设置为这些值之一。

这反过来又会触发以下响应式声明进行更新:

$: value = selectedValue

输入字段绑定到这个反应值:

<input type="text" bind:value>

所以点击“一”按钮将输入文本设置为“一”,点击“二”按钮将输入字段设置为“二”。

重要的是,您仍然可以在输入字段中输入任何内容


第二个组件被传递了两个数组值:

<Selector valueOne={[1, "one"]} valueTwo={[2, "two"]}/>

同样,单击按钮将selectedValue 设置为其中之一。

不过这次反应式声明依赖于一个数组元素:

$: value = selectedValue[1]

一切都和以前一样,除了现在您根本无法再在输入字段中输入内容

所以问题是 - 为什么&lt;input bind:value&gt; 对这两者的行为不同:

$: value = aString

$: value = anArray[x]

【问题讨论】:

    标签: svelte-3


    【解决方案1】:

    这似乎只是使用双向绑定时的问题。

    通过切换到单向和 on:input 处理程序,问题就消失了:

    即而不是这个:

    <input type="text" bind:value={valX}/>
    

    使用这个:

    <input type="text" value={valX} on:input={e => valX = e.target.value}/>
    

    【讨论】:

      【解决方案2】:

      我很确定您的响应式声明会在您的绑定值发生更改时立即覆盖它,即输入上的每一次击键和每一次按下按钮。这意味着它在技术上是有效的,你只是在每次它改变时恢复它。查看使用观察者的this version

      还绑定到响应式声明意味着您实际上永远不会使用输入更改变量(您可以在输入输入时在第一个选择器上的 JSON 结果中看到该值不会仅在按钮单击时更新)。

      为什么不丢失响应式声明并直接绑定到您想要的变量。然后使用{#if} 块根据index 的真实性在您显示的输入版本之间切换?

      <script>
          export let valueOne;
          export let valueTwo;
          export let index;
      
          let selectedValue = index? [] : '';
          let selectValue = (val) => selectedValue = val;
      </script>
      {#if index}
          <input type="text" bind:value={selectedValue[index]} placeholder="Type anything...">
      {:else}
          <input type="text" bind:value={selectedValue} placeholder="Type anything...">
      {/if}
      <button on:click={() => selectValue(valueOne)}>One</button>
      <button on:click={() => selectValue(valueTwo)}>Two</button>
      <p>
          <strong>Selected value:</strong> {JSON.stringify(selectedValue)}
      </p>
      

      通过直接绑定到 selectedValue 或其索引,您可以获得使用输入更改值的额外好处。这是REPL中的一个工作示例

      【讨论】:

      • 我不太明白...在值是字符串的示例中,如果我添加相同的$: value, console.log(value) 语句,绑定值肯定会在键入时更新?只有阵列版本不起作用。我没有直接绑定到 selectedValue 的原因是 REPL 是一个人为的例子来演示这个问题。现实情况是,我正在构建一个 ComboBox(a.k.a typeahead,autocomplete..)组件,其中建议(对象数组)显示为用户类型。进行选择时,我将绑定值设置为所选对象的属性。
      • 在您设计的示例中,反应性语句不需要是反应性的(索引是在装载时设置的)并且会导致问题。它正在覆盖value,当数据是字符串而不是数组时,出于某种原因这很好。您可以添加一个 setTimeout 来查看它是否会延迟 $: setTimeout(()=&gt; value = index ? selectedValue[index] : selectedValue, 200) 覆盖。如果您想要单向绑定,您可以在函数中设置绑定,例如 this。在没有看到的情况下不确定您的组合框。
      • "当数据是字符串而不是数组时,出于某种原因这很好" - 是的,这最终是我希望有人可以帮助回答的问题我。 (当然,有很多解决方法,但我真的想了解数组与字符串行为不同的根本原因。我非常感谢您建议的解决方法,但您实际上并没有回答这个问题。)
      • 它似乎是设置到值而不是绑定到它(实际上都没有绑定到 selectedValue 只是引用 selectedValue 的值),但我仍然不明白你为什么需要使用它在这种情况下。在您的示例中,不需要对要绑定的值进行反应性声明,因为在组件上设置了索引,即使在安装后更改了重新分配,也可以在导致更改的函数中处理重新分配。我不知道您的问题是否有一个简单的答案,但您似乎一开始就错误地使用了反应式声明。
      猜你喜欢
      • 1970-01-01
      • 2022-08-23
      • 2016-03-06
      • 1970-01-01
      • 1970-01-01
      • 2022-11-01
      • 2012-02-07
      • 1970-01-01
      • 2021-05-24
      相关资源
      最近更新 更多