facebook - lista - scrollview react native
Advertencia: cada elemento secundario en una matriz o iterador debe tener un accesorio único "clave". Verifique el método de renderizado de `ListView` (14)
Creé
una aplicación con
ReactNative
tanto para iOS como para Android con
ListView
.
Al llenar la vista de lista con una fuente de datos válida, la siguiente advertencia se imprime en la parte inferior de la pantalla:
Advertencia: cada elemento secundario en una matriz o iterador debe tener un accesorio "clave" único. Verifique el método de renderizado de
ListView
.
¿Cuál es el propósito de esta advertencia? Después del mensaje, enlazan a esta página , donde se discuten diferentes cosas que no tienen nada que ver con react native, sino con reactjs basado en web.
Mi ListView está construido con esas declaraciones:
render() {
var store = this.props.store;
return (
<ListView
dataSource={this.state.dataSource}
renderHeader={this.renderHeader.bind(this)}
renderRow={this.renderDetailItem.bind(this)}
renderSeparator={this.renderSeparator.bind(this)}
style={styles.listView}
/>
);
}
Mi fuente de datos consta de algo como:
var detailItems = [];
detailItems.push( new DetailItem(''plain'', store.address) );
detailItems.push( new DetailItem(''map'', '''') );
if(store.telefon) {
detailItems.push( new DetailItem(''contact'', store.telefon, ''Anrufen'', ''fontawesome|phone'') );
}
if(store.email) {
detailItems.push( new DetailItem(''contact'', store.email, ''Email'', ''fontawesome|envelope'') );
}
detailItems.push( new DetailItem(''moreInfo'', '''') );
this.setState({
dataSource: this.state.dataSource.cloneWithRows(detailItems)
});
Y las filas ListView se representan con cosas como:
return (
<TouchableHighlight underlayColor=''#dddddd''>
<View style={styles.infoRow}>
<Icon
name={item.icon}
size={30}
color=''gray''
style={styles.contactIcon}
/>
<View style={{ flex: 1}}>
<Text style={styles.headline}>{item.headline}</Text>
<Text style={styles.details}>{item.text}</Text>
</View>
<View style={styles.separator}/>
</View>
</TouchableHighlight>
);
Todo funciona bien y como se esperaba, excepto la advertencia que parece ser una completa tontería para mí.
Agregar una propiedad clave a mi clase "DetailItem" no resolvió el problema.
Esto es, lo que realmente se pasará a ListView como resultado de "cloneWithRows":
_dataBlob:
I/ReactNativeJS( 1293): { s1:
I/ReactNativeJS( 1293): [ { key: 2,
I/ReactNativeJS( 1293): type: ''plain'',
I/ReactNativeJS( 1293): text: ''xxxxxxxxxx'',
I/ReactNativeJS( 1293): headline: '''',
I/ReactNativeJS( 1293): icon: '''' },
I/ReactNativeJS( 1293): { key: 3, type: ''map'', text: '''', headline: '''', icon: '''' },
I/ReactNativeJS( 1293): { key: 4,
I/ReactNativeJS( 1293): type: ''contact'',
I/ReactNativeJS( 1293): text: ''(xxxx) yyyyyy'',
I/ReactNativeJS( 1293): headline: ''Anrufen'',
I/ReactNativeJS( 1293): icon: ''fontawesome|phone'' },
I/ReactNativeJS( 1293): { key: 5,
I/ReactNativeJS( 1293): type: ''contact'',
I/ReactNativeJS( 1293): text: ''[email protected]'',
I/ReactNativeJS( 1293): headline: ''Email'',
I/ReactNativeJS( 1293): icon: ''fontawesome|envelope'' },
I/ReactNativeJS( 1293): { key: 6, type: ''moreInfo'', text: '''', headline: '''', icon: '''' } ] },
Como se ve en una clave, cada registro tiene una propiedad clave. La advertencia aún existe.
Agregue una ''clave'' de apoyo al componente raíz de representación de la lista.
<ScrollView>
<List>
{this.state.nationalities.map((prop, key) => {
return (
<ListItem key={key}>
<Text>{prop.name}</Text>
</ListItem>
);
})}
</List>
</ScrollView>
Aquí se basa en mi comprensión.
Espero que sea útil.
Se supone que representa una lista de cualquier componente como el ejemplo detrás.
La etiqueta raíz de cada componente debe tener una
key
.
No tiene que ser único.
No puede ser
key=0
,
key=''0''
, etc. Parece que la clave es inútil.
render() {
return [
(<div key={0}> div 0</div>),
(<div key={1}> div 2</div>),
(<table key={2}><tbody><tr><td> table </td></tr></tbody></table>),
(<form key={3}> form </form>),
];
}
Cambia tu código de:
render() {
return (
<ol>
{this.props.results.map((result) => (
<li>{result.text}</li>
))}
</ol>
);
}
A:
render() {
return (
<ol>
{this.props.results.map((result) => (
<li key={result.id}>{result.text}</li>
))}
</ol>
);
}
Entonces resuelto.
Comprobar: clave = undef !!!
También recibiste el mensaje de advertencia:
Each child in a list should have a unique "key" prop.
si su código está completo bien, pero si está activado
<MyComponent key={someValue} />
someValue es indefinido !!! Por favor verifique esto primero. Puedes ahorrar horas.
El código específico que usé para solucionar esto fue:
renderSeparator(sectionID, rowID, adjacentRowHighlighted) {
return (
<View style={styles.separator} key={`${sectionID}-${rowID}`}/>
)
}
Incluyo el código específico porque necesita que las claves sean únicas, incluso para los separadores. Si hace algo similar, por ejemplo, si establece esto en una constante, obtendrá otro error molesto sobre la reutilización de las claves. Si no conoce JSX, construir la devolución de llamada a JS para ejecutar las distintas partes puede ser bastante complicado.
Y en ListView, obviamente adjuntando esto:
<ListView
style={styles.listview}
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}
renderSeparator={this.renderSeparator.bind(this)}
renderSectionHeader={this.renderSectionHeader.bind(this)}/>
Gracias a Coldbuffet y a Nader Dabit que me señalaron este camino.
Esta advertencia se produce cuando no agrega una clave a los elementos de su lista. Según react js Docs:
Las teclas ayudan a React a identificar qué elementos han cambiado, se agregan o se eliminan. Se deben dar claves a los elementos dentro de la matriz para darles una identidad estable:
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
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:
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
Cuando no tiene ID estables para los elementos renderizados, puede usar el índice de elementos como clave como último recurso
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
Esto no puede ser enfatizado suficientemente:
Las claves solo tienen sentido en el contexto de la matriz circundante .
"Por ejemplo, si extrae un componente ListItem, debe mantener la clave en los elementos <ListItem /> en la matriz en lugar de en el elemento <li> en el propio ListItem". - https://reactjs.org/docs/lists-and-keys.html#extracting-components-with-keys
He tenido exactamente el mismo problema que tú por un tiempo, y después de mirar algunas de las sugerencias anteriores, finalmente resolví el problema.
Resulta que (al menos para mí de todos modos), necesitaba proporcionar una clave (un accesorio llamado ''clave'') al componente que estoy volviendo de mi método renderSeparator. Agregar una clave a mi renderRow o renderSectionHeader no hizo nada, pero agregarlo a renderSeparator hizo que la advertencia desapareciera.
Espero que ayude.
Lo arreglé agregando una propiedad a renderSeparator Component, el código está aquí:
_renderSeparator(sectionID,rowID){
return (
<View style={styles.separatorLine} key={"sectionID_"+sectionID+"_rowID_"+rowID}></View>
);
}
Las palabras clave de esta advertencia son "único", sectionID + rowID devuelven un valor único en ListView.
Necesita proporcionar una clave .
Intente hacer esto en sus filas ListView si tiene una propiedad clave:
<TouchableHighlight key={item.key} underlayColor=''#dddddd''>
Si no, intente simplemente agregar el elemento como clave:
<TouchableHighlight key={item} underlayColor=''#dddddd''>
Parece que ambas condiciones se cumplen, quizás la clave (''contacto'') es el problema
if(store.telefon) {
detailItems.push( new DetailItem(''contact'', store.telefon, ''Anrufen'', ''fontawesome|phone'') );
}
if(store.email) {
detailItems.push( new DetailItem(''contact'', store.email, ''Email'', ''fontawesome|envelope'') );
}
Si está utilizando el elemento
<Fade in>
para una aplicación de reacción, agregue también el atributo
key={}
o verá un error en la consola.
Suponiendo que el método renderDetailItem tiene la siguiente firma ...
(rowData, sectionID, rowID, highlightRow)
Intenta hacer esto ...
<TouchableHighlight key={rowID} underlayColor=''#dddddd''>
También puede usar el recuento de iteraciones (i) como
key
:
render() {
return (
<ol>
{this.props.results.map((result, i) => (
<li key={i}>{result.text}</li>
))}
</ol>
);
}