cloneElement
Referencia
cloneElement(elemento, props, ...children)
Llama a cloneElement
para crear un elemento React basado en el elemento
, pero con diferentes props
y children
:
Parámetros
elemento
: El argumentoelemento
debe ser un elemento de React válido. Por ejemplo, podría ser un nodo JSX como<Something />
, el resultado de llamar a , o el resultado de otra llamada acloneElement
.props
: El argumentoprops
debe ser un objeto onull
. Si pasasnull
, el elemento clonado mantendrá todos loselement.props
originales. De lo contrario, para cada propiedad en el objetoprops
, el elemento devuelto “preferirá” el valor deprops
sobre el valor deelement.props
. El resto de las propiedades se completarán a partir de loselement.props
originales. Si pasasprops.key
oprops.ref
, reemplazarán a los originales.opcional
...children
: Cero o más nodos hijo. Pueden ser cualquier nodo React, incluidos elementos de React, cadenas, números, , nodos vacíos (null
,undefined
,true
, yfalse
), y arrays de nodos de React. Si no pasas ningún argumento...children
, se conservarán loselement.props.children
originales.
Devuelve
cloneElement
devuelve un objeto de elemento de React con algunas propiedades:
type
: Igual queelement.type
.props
: El resultado de mezclar superficialmenteelement.props
con lasprops
que has pasado para sobrescribirlas.ref
: Elelement.ref
original, a menos que se haya sobrescrito conprops.ref
.key
: Elelement.key
original, a menos que se haya sobrescrito conprops.key
.
Usualmente, devolverás el elemento desde tu componente o lo harás hijo de otro elemento. Aunque puedes leer las propiedades del elemento, es mejor tratar a cada elemento como opaco después de que se crea, y solo renderizarlo.
Advertencias
Clonar un elemento no modifica el elemento original.
Solo debes pasar hijos como múltiples argumentos a
createElement
si todos son conocidos estáticamente, comocloneElement(element, null, child1, child2, child3)
. Si tus hijos son dinámicos, pasa todo el array como tercer argumento:cloneElement(element, null, listItems)
. Esto garantiza que React te para cualquier lista dinámica. Para listas estáticas no es necesario porque nunca se reordenan.cloneElement
hace que sea más difícil rastrear el flujo de datos, por lo que prueba las en su lugar.
Uso
Sobrescribir props de un elemento
Para sobrescribir las props de algún elemento de React, pásalo a cloneElement
con las props que quieres sobrescribir:
Aquí, el elemento clonado resultante será <Row title="Col" isHighlighted={true} />
.
Veamos un ejemplo para ver cuándo es útil.
Imagina un componente List
que renderiza sus como una lista de filas seleccionables con un botón “Siguiente” que cambia qué fila está seleccionada. El componente List
necesita renderizar la Row
seleccionada de manera diferente, por lo que clona cada hijo <Row>
que ha recibido y agrega una propiedad extra isHighlighted: true
o isHighlighted: false
:
Digamos que el JSX original recibido por List
se ve así:
Clonando sus hijos, List
puede pasar información adicional a cada Row
dentro. El resultado se ve así:
Observa cómo al presionar “Siguiente” se actualiza el estado del List
, y resalta una fila diferente:
Para resumir, List
clonó los elementos <Row />
que recibió y les agregó una propiedad extra.
Alternativas
Pasar datos con una prop de renderizado
En vez de usar cloneElement
, considera aceptar una render prop (o prop de renderizado) como renderItem
. Aquí, List
recibe renderItem
como una prop. List
llama a renderItem
para cada elemento y pasa isHighlighted
como un argumento:
La prop renderItem
se llama una “render prop” porque es una propiedad que especifica cómo renderizar algo. Por ejemplo, puedes pasar una implementación de renderItem
que renderice un <Row>
con el valor isHighlighted
dado:
El resultado final es el mismo que con cloneElement
:
Sin embargo, puedes rastrear claramente de dónde viene el valor isHighlighted
.
Este patrón es preferido a cloneElement
porque es más explícito.
Pasar datos a través del contexto
Otra alternativa a cloneElement
es
Por ejemplo, puedes llamar a para definir un HighlightContext
:
Tu componente List
puede envolver cada elemento que renderiza en un proveedor de HighlightContext
:
Con este enfoque, Row
no necesita recibir una propiedad isHighlighted
en absoluto. En su lugar, lee del contexto:
Esto permite que el componente que llama no sepa o se preocupe por pasar isHighlighted
a <Row>
:
En vez de eso, List
y Row
coordinan la lógica de resaltado a través del contexto.
Extraer lógica en un Hook personalizado
Otro enfoque que puedes probar es extraer la lógica “no visual” en tu propio Hook, y usar la información devuelta por tu Hook para decidir qué renderizar. Por ejemplo, puedes escribir un Hook personalizado useList
como este:
Luego puedes usarlo así:
El flujo de datos es explícito, pero el estado está dentro del Hook personalizado useList
que puedes usar desde cualquier componente:
Este enfoque es particularmente útil si quieres reutilizar esta lógica entre diferentes componentes.