De seguro en más de una ocasión te has encontrado con el siguiente mensaje de error cuando estás renderizando múltiples elementos con React.
Y como siempre, el consejo es seguir las indicaciones del mensaje de error, para resolver este mensaje simplemente agregamos la prop key
con un valor cualquiera y resuelto ¿no? Pero, ¿por qué necesitas definir esta prop? y ¿para qué sirve?
Para encontrar respuesta a estas preguntas revisemos primero como funciona React a la hora de renderizar múltiples elementos como una lista o una colección de contenedores div
.
El problema
Tienes un componente que renderiza una lista variable de datos que provienen desde las props, es decir algo similar a esto
Tu componente simplemente itera sobre la lista de items utilizando Array.map
que para cada elemento de la lista retorna un nuevo componente llamado 'Item' que a su vez renderiza el atributo valor del elemento.
Para saber más sobre Array.map y otros métodos de arreglos visita nuestra Guía Definitiva de Métodos de Arreglos
Aquí aparece el error que mencioné al prinicipio, diciendo que debes agregar una nueva prop al <Item>
renderizado
¿Recuerdas que es el Virtual DOM?
React hace uso de un concepto llamado Virtual DOM, básicamente es una representación del DOM en forma de árbol de objetos, una abstracción que busca que los cambios - re-renders - sean más fáciles de calcular. React utiliza esta estructura para definir el cambió entre un estado y otro, obteniendo un “diff”. Luego usa esta información para actualizar el DOM sólo donde sea necesario.
Esta es una representación visual de la idea propuesta:
¿Por qué React necesita la prop key
?
Ahora que ya recordaste cómo funciona el Virtual DOM, es hora de revisar cómo se relaciona aquello con el proceso de renderizado de una colección de datos y componentes.
La prop key
es utilizada por React para mantener un registro de los elementos que han cambiado, es decir, son utilizadas para dar una "identidad" a los elementos de la lista.
React, es un espectador de tu código, no conoce los detalles de implementación de tu aplicación, sólo puede ver la función que le pasas, y React simplemente responde con la conversión de función a elementos React.
Hasta este punto, a pesar de que se emite el warning, React sabe como renderizar esos elementos en pantalla, el problema yace cuando esta lista, por alguna razón (como un cambio en el estado interno del componente) es renderizada nuevamente, y por esa misma razón su contenido cambió.
Al generarse un re-render React realiza un cálculo del “diff” de lo que se renderizo en el paso anterior y lo que buscas renderizar en el paso actual, digamos que ese diff en este caso es simplemente la eliminación del segundo elemento de la lista y el renombre del tercer item, resultando en algo así:
Pero ahora, ¿cómo React define que acciones deben tomarse para que esto sea el resultado esperado? Algunas posibles acciones son:
- Eliminar el segundo item y renombrar el tercero.
- Eliminar el segundo y tercer item y agregar un nuevo item.
- Eliminar el tercer item y renombrar el segundo.
Ahora ya se puso algo confuso ¿verdad?, como React no sabe los detalles de tu implementación, la única opción es tratar de adivinar y jugar su mejor carta: Asumir que el index
del elemento actúa como la prop key
, es decir, es único y "estable" (no cambia con el tiempo).
El resultado de esta heurística es en efecto: Renombrar el segundo item y eliminar el tercero, lo que no es exactamente lo que ocurrió ¿no?
Esta necesidad de mantener un registro de cambios en una lista donde los elementos renderizados son casi idénticos es lo que da nacimiento a la prop key
.
¿Para qué sirve la prop key?
Entonces, la prop key
le permite a React identificar un elemento en particular dentro de una colección y para que este cometido se logre de forma fehaciente, el valor pasado a la prop key debe ser único, irrepetible y estable, es decir, debe ser el mismo valor asignado a un mismo elemento durante todo el ciclo de vida del componente.
Entonces volviendo al ejemplo. Digamos que nuestros datos tienen un atributo llamado id
que es un hash que proviene de la colección original de datos, como una base de datos.
Lo que queremos lograr es renombrar el tercer item y eliminar el segundo item.
El resultado de nuestro cambio sería así:
Donde gracias a la key
, tanto tú como React pueden ver con claridad que el segundo item fue eliminado y el tercero renombrado.
Quizá un demo sea más adecuado para revisar estos ejemplos:
https://codesandbox.io/s/react-array-keys-qmwwk?from-embed=&file=/src/App.js
El demo inicialmente no utiliza la prop key
. Juega un poco con él agregando y eliminando elementos, ¿qué ocurre?, ¿qué problema encuentras?
Luego sigue los comentarios y agrega la prop key
y compara el comportamiento. ¿Los problemas identificados siguen ahí?
Conclusión
En resumen, React no tiene forma de conocer de antemano los detalles de implementación de tu código y los cambios ejercidos sobre tus datos dentro de una colección. Este desconocimiento es el que crea el requerimiento de tener una prop que le de información a React para saber qué hacer cuando una colección de elementos cambia. El valor usado en la prop key
debe ser un valor invariable en el tiempo que permita identificar un elemento en concreto, es decir, usar el index
generado por Array.map
no es válido.