javascript - logo - react js vs angular
Comprender las claves Ășnicas para los hijos de la matriz en React.js (7)
Estoy creando un componente React que acepta una fuente de datos JSON y crea una tabla ordenable.
Cada una de las filas de datos dinámicos tiene asignada una clave única, pero sigo recibiendo un error de:
Cada niño en una matriz debe tener un accesorio "clave" único.
Verifique el método de renderizado de TableComponent.
Mi método de renderizado
TableComponent
devuelve:
<table>
<thead key="thead">
<TableHeader columns={columnNames}/>
</thead>
<tbody key="tbody">
{ rows }
</tbody>
</table>
El componente
TableHeader
es una sola fila y también tiene asignada una clave única.
Cada
row
en
rows
se construye a partir de un componente con una clave única:
<TableRowItem key={item.id} data={item} columns={columnNames}/>
Y el
TableRowItem
ve así:
var TableRowItem = React.createClass({
render: function() {
var td = function() {
return this.props.columns.map(function(c) {
return <td key={this.props.data[c]}>{this.props.data[c]}</td>;
}, this);
}.bind(this);
return (
<tr>{ td(this.props.item) }</tr>
)
}
});
¿Qué está causando el error único de la llave de apoyo?
Advertencia: cada elemento secundario en una matriz o iterador debe tener un accesorio "clave" único.
Esta es una advertencia ya que los elementos de la matriz sobre los que vamos a iterar necesitarán un parecido único.
React maneja la representación iterativa de componentes como matrices.
Una mejor manera de resolver esto es proporcionar un índice sobre los elementos de la matriz sobre los que va a iterar, por ejemplo:
Each child in a list should have a unique "key" prop.
El índice es React props incorporado.
Comprobar: clave = undef !!!
También recibiste el mensaje de advertencia:
<ObjectRow key={someValue} />
si su código está completo bien, pero si está activado
class UsersState extends Component
{
state = {
users: [
{name:"shashank", age:20},
{name:"vardan", age:30},
{name:"somya", age:40}
]
}
render()
{
return(
<div>
{
this.state.users.map((user, index)=>{
return <UserState key={index} age={user.age}>{user.name}</UserState>
})
}
</div>
)
}
someValue es indefinido !!! Por favor verifique esto primero. Puedes ahorrar horas.
Debe agregar una clave a cada elemento secundario , así como a cada elemento dentro de los elementos secundarios.
De esta forma, React puede manejar el mínimo cambio de DOM.
En su código, cada
<TableRowItem key={item.id} data={item} columns={columnNames}/>
está intentando renderizar a algunos niños dentro de ellos sin una clave.
Mira este ejemplo .
Intente eliminar la
key={i}
del elemento
<b></b>
dentro del div (y verifique la consola).
En la muestra, si no le damos una clave al elemento
<b>
y queremos actualizar
solo
el
object.city
, React necesita volver a representar toda la fila frente al elemento.
Aquí está el código:
var data = [{name:''Jhon'', age:28, city:''HO''},
{name:''Onhj'', age:82, city:''HN''},
{name:''Nohj'', age:41, city:''IT''}
];
var Hello = React.createClass({
render: function() {
var _data = this.props.info;
console.log(_data);
return(
<div>
{_data.map(function(object, i){
return <div className={"row"} key={i}>
{[ object.name ,
// remove the key
<b className="fosfo" key={i}> {object.city} </b> ,
object.age
]}
</div>;
})}
</div>
);
}
});
React.render(<Hello info={data} />, document.body);
La respuesta publicada por @Chris en la parte inferior entra en mucho más detalle que esta respuesta. Por favor, eche un vistazo a https://.com/a/43892905/2325522
Reaccione la documentación sobre la importancia de las claves en la reconciliación: Keys
Esta es una advertencia, pero abordar esto hará que Reacts se vuelva mucho MÁS RÁPIDO ,
Esto se debe a que
React
necesita identificar de forma única cada elemento de la lista.
Digamos que si el estado de un elemento de esa lista cambia en Reacts
Virtual DOM
entonces React necesita averiguar qué elemento se modificó y en qué parte del DOM debe cambiar para que el DOM del navegador esté sincronizado con Reacts Virtual DOM.
Como solución, simplemente introduzca un atributo
key
para cada etiqueta
li
.
Esta
key
debe ser un valor único para cada elemento.
Lo arreglé usando Guid para cada clave como esta: Generando Guid:
guid() {
return this.s4() + this.s4() + ''-'' + this.s4() + ''-'' + this.s4() + ''-'' +
this.s4() + ''-'' + this.s4() + this.s4() + this.s4();
}
s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
Y luego asignando este valor a los marcadores:
{this.state.markers.map(marker => (
<MapView.Marker
key={this.guid()}
coordinate={marker.coordinates}
title={marker.title}
/>
))}
Simplemente agregue la clave única a sus Componentes
data.map((marker)=>{
return(
<YourComponents
key={data.id} // <----- unique key
/>
);
})
¡Tenga cuidado al iterar sobre matrices!
Es un error común pensar que usar el índice del elemento en la matriz es una forma aceptable de suprimir el error con el que probablemente esté familiarizado:
Each child in an array should have a unique "key" prop.
Sin embargo, en muchos casos no lo es. Este es un antipatrón que, en algunas situaciones, puede conducir a un comportamiento no deseado .
Comprender la
key
apoyo
React utiliza la
key
apoyo para comprender la relación de elemento componente a DOM, que luego se utiliza para el
proceso de reconciliación
.
Por lo tanto, es muy importante que la clave
siempre sea
única
, de lo contrario, hay una buena posibilidad de que React mezcle los elementos y mute el incorrecto.
También es importante que estas claves
permanezcan estáticas
en todos los renders para mantener el mejor rendimiento.
Dicho esto, no siempre es necesario aplicar lo anterior, siempre que se sepa que la matriz es completamente estática. Sin embargo, se recomienda aplicar las mejores prácticas siempre que sea posible.
Un desarrollador de React dijo en github.com/facebook/react/issues/1342#issuecomment-39230939 :
- La clave no se trata realmente de rendimiento, se trata más de identidad (que a su vez conduce a un mejor rendimiento). Los valores cambiantes y asignados al azar no son identidad
- Realmente no podemos proporcionar claves [automáticamente] sin saber cómo se modelan sus datos. Sugeriría tal vez usar algún tipo de función de hash si no tiene identificadores
- Ya tenemos claves internas cuando usamos matrices, pero son el índice en la matriz. Cuando inserta un nuevo elemento, esas claves son incorrectas.
En resumen, una
key
debería ser:
- Único : una clave no puede ser idéntica a la de un componente hermano .
- Estático : una clave nunca debe cambiar entre los renders.
Usando la
key
apoyo
Según la explicación anterior, estudie cuidadosamente las siguientes muestras e intente implementar, cuando sea posible, el enfoque recomendado.
Malo (potencialmente)
<tbody>
{rows.map((row, i) => {
return <ObjectRow key={i} />;
})}
</tbody>
Este es posiblemente el error más común visto al iterar sobre una matriz en React. Este enfoque no es técnicamente "incorrecto" , es simplemente ... "peligroso" si no sabe lo que está haciendo. Si está iterando a través de una matriz estática, este es un enfoque perfectamente válido (por ejemplo, una matriz de enlaces en su menú de navegación). Sin embargo, si agrega, elimina, reordena o filtra elementos, debe tener cuidado. Eche un vistazo a esta explicación detallada en la documentación oficial.
class MyApp extends React.Component {
constructor() {
super();
this.state = {
arr: ["Item 1"]
}
}
click = () => {
this.setState({
arr: [''Item '' + (this.state.arr.length+1)].concat(this.state.arr),
});
}
render() {
return(
<div>
<button onClick={this.click}>Add</button>
<ul>
{this.state.arr.map(
(item, i) => <Item key={i} text={"Item " + i}>{item + " "}</Item>
)}
</ul>
</div>
);
}
}
const Item = (props) => {
return (
<li>
<label>{props.children}</label>
<input value={props.text} />
</li>
);
}
ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
En este fragmento estamos usando una matriz no estática y no nos estamos restringiendo a usarla como una pila.
Este es un enfoque inseguro (verá por qué).
Observe cómo a medida que agregamos elementos al comienzo de la matriz (básicamente sin desplazamiento), el valor para cada
<input>
permanece en su lugar.
¿Por qué?
Porque la
key
no identifica de forma exclusiva cada elemento.
En otras palabras, al principio el
Item 1
tiene la
key={0}
.
Cuando agregamos el segundo elemento, el elemento superior se convierte en el
Item 2
, seguido del
Item 1
como el segundo elemento.
Sin embargo, ahora el
Item 1
tiene
key={1}
y ya no
key={0}
.
¡En cambio, el
Item 2
ahora tiene
key={0}
!
Como tal, React piensa que los elementos
<input>
no han cambiado, ¡porque el
Item
con la clave
0
siempre está en la parte superior!
Entonces, ¿por qué este enfoque solo a veces es malo?
Este enfoque solo es arriesgado si la matriz se filtra, reorganiza o se agregan / eliminan elementos.
Si siempre es estático, entonces es perfectamente seguro de usar.
Por ejemplo, un menú de navegación como
["Home", "Products", "Contact us"]
se puede iterar de forma segura con este método porque probablemente nunca agregará nuevos enlaces ni los reorganizará.
En resumen, aquí es cuando puede usar el índice de
forma segura
como
key
:
- La matriz es estática y nunca cambiará.
- La matriz nunca se filtra (muestra un subconjunto de la matriz).
- La matriz nunca se reordena.
- La matriz se usa como una pila o LIFO (última entrada, primera salida). En otras palabras, la adición solo se puede hacer al final de la matriz (es decir, push), y solo se puede eliminar el último elemento (es decir, pop).
Si, en cambio, en el fragmento anterior, empujáramos el elemento agregado al final de la matriz, el orden de cada elemento existente siempre sería correcto.
Muy mal
<tbody>
{rows.map((row) => {
return <ObjectRow key={Math.random()} />;
})}
</tbody>
Si bien este enfoque probablemente garantizará la unicidad de las claves,
siempre
obligará a reaccionar a volver a representar cada elemento de la lista, incluso cuando no sea necesario.
Esta es una solución muy mala, ya que afecta enormemente el rendimiento.
Sin mencionar que no se puede excluir la posibilidad de una colisión de teclas en el caso de que
Math.random()
produzca el mismo número dos veces.
Las claves inestables (como las producidas por
Math.random()
) harán que muchas instancias de componentes y nodos DOM se vuelvan a crear innecesariamente, lo que puede causar degradación del rendimiento y pérdida del estado en los componentes secundarios.
Muy bien
<tbody>
{rows.map((row) => {
return <ObjectRow key={row.uniqueId} />;
})}
</tbody>
Este es posiblemente el
mejor enfoque
porque utiliza una propiedad que es única para cada elemento del conjunto de datos.
Por ejemplo, si las
rows
contienen datos obtenidos de una base de datos, uno podría usar la Clave primaria de la tabla (
que generalmente es un número de incremento automático
).
La mejor manera de elegir una clave es usar una cadena que identifique de forma exclusiva un elemento de la lista entre sus hermanos. La mayoría de las veces usaría ID de sus datos como claves
Bueno
componentWillMount() {
let rows = this.props.rows.map(item => {
return {uid: SomeLibrary.generateUniqueID(), value: item};
});
}
...
<tbody>
{rows.map((row) => {
return <ObjectRow key={row.uid} />;
})}
</tbody>
Este también es un buen enfoque.
Si su conjunto de datos no contiene ningún dato que garantice la unicidad (
por ejemplo, una matriz de números arbitrarios
), existe la posibilidad de una colisión de teclas.
En tales casos, es mejor generar manualmente un identificador único para cada elemento en el conjunto de datos antes de iterar sobre él.
Preferiblemente al montar el componente o cuando se recibe el conjunto de datos (
por ejemplo, desde
props
o desde una llamada API asíncrona
), para hacer esto solo
una vez
, y no cada vez que el componente se vuelve a representar.
Ya hay un puñado de bibliotecas que pueden proporcionarle esas claves.
Aquí hay un ejemplo:
react-key-index
.