Why bind to index instead of value in a component with $bindable? #17880
|
Hello everyone, I am learning Svelte at the moment and have come across this behavior and cannot find an explanation to why the compiler wants me to write the code like this: I have a component TodoList.svelte that uses another component TodoItem.svelte. TodoList.svelte <script>
import TodoItem from "./TodoItem.svelte";
let { todos = $bindable(), removeTodo } = $props()
</script>
<ul>
{#each todos as todo, i}
<TodoItem bind:todo={todos[i]} {removeTodo}/>
{/each}
</ul>TodoItem.svelte <script>
import { slide } from "svelte/transition";
let { todo = $bindable(), removeTodo } = $props()
</script>
<li transition:slide>
<input type="checkbox" bind:checked={todo.completed}>
<input type="text" bind:value={todo.text}>
<button onclick="{() => removeTodo(todo)}">x</button>
</li>In TodoItem.svelte, I am binding to todo as I want to mutate it by activating/deactivating the checkbox and so mutate todo.completed. In TodoList.svelte I need to use Why do I need to pass the reference to the right todo object in the each loop by its index instead of directly using the value, like: {#each todos as todo, i}
<TodoItem bind:todo={todo} {removeTodo}/>
{/each}Thanks in advance! |
Replies: 2 comments 1 reply
|
Because it can be a derived array {#each todos.filter(isActive) as todo, i}
<TodoItem bind:todo={todo} {removeTodo}/>
{/each}or not an array ( {#each todoMap.values() as todo, i}
<TodoItem bind:todo={todo} {removeTodo}/>
{/each}and totally unclear to what bind {#each myObject.someField as todo, i}
<TodoItem bind:todo={todo} {removeTodo}/>
{/each}
For these reasons, we require explicitness here. |
|
I think this should be documented in the #each page. I had a couple of situations where using #each + #bind caused me some bugs. |
Because it can be a derived array
{#each todos.filter(isActive) as todo, i} <TodoItem bind:todo={todo} {removeTodo}/> {/each}or not an array (
#eachaccepts any iterable object):{#each todoMap.values() as todo, i} <TodoItem bind:todo={todo} {removeTodo}/> {/each}and totally unclear to what bind
todo. And even in a case like{#each myObject.someField as todo, i} <TodoItem bind:todo={todo} {removeTodo}/> {/each}someFieldmay each time return a new array that is not supposed to be mutated.For these reasons, we require explicitness here.