El índice reactivo en For y el valor reactivo en Index
For e Index tienen firmas de callback que son imágenes especulares: For entrega valor estático e índice reactivo; Index entrega valor reactivo e índice estático. La asimetría no es arbitraria, cae directamente de sobre qué clavea cada uno. Aquí se explica la dualidad y se aplica el índice-signal y el valor-signal en casos reales.
La dualidad exacta
Parte del principio único: lo reactivo es lo que varía mientras la fila permanece. En For, la fila está atada a una referencia de objeto; esa referencia no cambia en toda la vida de la fila —si cambiara, sería otra fila—, así que el item puede ser estático. Lo que sí puede cambiar sin destruir la fila es su posición, cuando la lista se reordena; por eso el index es un accessor. En Index ocurre lo simétrico: la fila está atada a una posición fija, así que el index es un número estático, y lo que cambia bajo esa posición es el valor, de ahí que el item sea un accessor.
// For: valor estatico, indice reactivo<For each={items()}> {(item, indice) => <li>{indice()}: {item.nombre}</li>}</For>// Index: valor reactivo, indice estatico<Index each={items()}> {(item, indice) => <li>{indice}: {item().nombre}</li>}</Index>Memoriza la regla y olvida la tabla: en cada componente, lo que se llama con paréntesis es lo variable, y lo que se lee sin paréntesis es el invariante. For invariante en el objeto, variable en la posición; Index invariante en la posición, variable en el valor.
El índice-signal de For en la práctica
Que el índice de For sea reactivo no es un detalle académico: es lo que permite que una numeración, un rayado cebra o una insignia de “primero” sigan siendo correctos tras un reordenamiento sin recrear filas. Cuando mueves un objeto, su nodo se reubica y su index() se recomputa solo; las clases y los números que dependen de él se actualizan de grano fino.
<For each={jugadores()}> {(jugador, posicion) => ( <li classList={{ lider: posicion() === 0 }}> #{posicion() + 1} — {jugador.nombre} </li> )}</For>Reordena la lista y la clase lider salta a la nueva primera fila, y el número #n de cada fila se recalcula, todo sin desmontar ni un solo li. El estado local de cada fila permanece, porque el nodo solo se movió; únicamente el binding que lee posicion() reacciona.
El valor-signal de Index en la práctica
En Index el accessor es el item, y ese es justo el mecanismo que hace de Index la herramienta de los campos editables. El nodo del input se ancla a la posición; cuando el dato de esa posición cambia —lo escribas tú o llegue del servidor—, fluye por item() y solo el binding del value reacciona, sin tocar el elemento. El foco, el cursor y la selección se quedan donde el usuario los dejó.
<Index each={campos()}> {(campo, i) => ( <input value={campo().valor} onInput={(e) => actualizar(i, e.currentTarget.value)} /> )}</Index>Observa la división de trabajo: campo() es reactivo y alimenta el value; i es un número estático perfecto para localizar qué posición actualizar en el manejador, porque para ese input la posición nunca cambia. Con For esta misma escena se rompería —al cambiar el valor cambiaría la clave del primitivo y el input se remontaría—, y con Index encaja sin fricción.
Combinar los dos signals en una fila
La potencia real aparece cuando una fila deriva de su miembro reactivo. En For, combinas el índice-signal con el objeto estático para producir vistas que reaccionan solo a lo que cambia: el id no reacciona nunca, la posición sí.
<For each={pistas()}> {(pista, i) => { const par = () => i() % 2 === 0; // deriva del indice-signal return ( <li classList={{ par: par(), impar: !par() }}> {i() + 1}. {pista.titulo} </li> ); }}</For>La derivación par se recomputa solo cuando i() cambia, es decir, cuando esa fila se reordena; el título, estático, no participa. En Index la derivación es simétrica: parte del valor-signal, y el índice es una constante que puedes capturar sin miedo en un closure porque no cambiará para esa fila.
<Index each={temperaturas()}> {(t, i) => { const alerta = () => t() > 38; // deriva del valor-signal return <li classList={{ alerta: alerta() }}>sensor {i}: {t()}</li>; }}</Index>Aquí i entra en el closure como número literal —seguro, porque la posición es el invariante— mientras t() es la fuente reactiva que dispara alerta. Este patrón de derivar con una función que lee el miembro reactivo es el idioma que sustituye a useMemo: no declaras dependencias, la derivación se suscribe sola a lo que lee, sea i() o t(), y se recomputa solo cuando eso cambia. La precisión es automática.
Cuando la derivación es cara, promuévela a un createMemo explícito; hereda la misma suscripción fina al miembro reactivo:
<For each={filas()}> {(fila, i) => { const etiqueta = createMemo(() => `${i() + 1} de ${total()}`); return <li>{etiqueta()}</li>; }}</For>