我使用<{3}}为iOS和Android构建了一个带 ReactNative 的应用。使用有效数据源填充列表视图时,屏幕底部会显示以下警告:
警告:数组或迭代器中的每个子节点都应该有一个唯一的“键” 支柱。检查
ListView
的呈现方法。
此警告的目的是什么?在他们链接到ListView
之后的消息之后,讨论完全不同的事情与本机反应无关,但与基于网络的反应有关。
我的ListView是使用这些语句构建的:
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}
/>
);
}
我的DataSource包含以下内容:
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)
});
ListView-Rows使用以下内容进行渲染:
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>
);
一切正常并且如预期的那样,除了警告似乎对我来说完全无稽之谈。
将key属性添加到我的“DetailItem”-Class并没有解决问题。
这就是由于“cloneWithRows”而真正传递给ListView的内容:
_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: 'xxxxxxxxx@hotmail.com',
I/ReactNativeJS( 1293): headline: 'Email',
I/ReactNativeJS( 1293): icon: 'fontawesome|envelope' },
I/ReactNativeJS( 1293): { key: 6, type: 'moreInfo', text: '', headline: '', icon: '' } ] },
如一键看,每条记录都有一个关键属性。警告仍然存在。
答案 0 :(得分:71)
我现在已经和你一样完全同样的问题了,在看了上面的一些建议之后,我终于解决了这个问题。
事实证明(至少对我而言),我需要为我从renderSeparator方法返回的组件提供一个键(一个名为'key'的道具)。向renderRow或renderSectionHeader添加一个键没有做任何事情,但是将它添加到renderSeparator会使警告消失。
希望有所帮助。
答案 1 :(得分:59)
您需要提供密钥。
如果您有一个关键属性,请尝试在ListView Rows中执行此操作:
<TouchableHighlight key={item.key} underlayColor='#dddddd'>
如果没有,请尝试将该项目添加为关键字:
<TouchableHighlight key={item} underlayColor='#dddddd'>
答案 2 :(得分:29)
您还可以将迭代计数(i)用作key
:
render() {
return (
<ol>
{this.props.results.map((result, i) => (
<li key={i}>{result.text}</li>
))}
</ol>
);
}
答案 3 :(得分:17)
更改您的代码:
render() {
return (
<ol>
{this.props.results.map((result) => (
<li>{result.text}</li>
))}
</ol>
);
}
致:
render() {
return (
<ol>
{this.props.results.map((result) => (
<li key={result.id}>{result.text}</li>
))}
</ol>
);
}
然后解决了。
答案 4 :(得分:6)
在列表的呈现根组件中添加道具“键”。
<ScrollView>
<List>
{this.state.nationalities.map((prop, key) => {
return (
<ListItem key={key}>
<Text>{prop.name}</Text>
</ListItem>
);
})}
</List>
</ScrollView>
答案 5 :(得分:5)
当您未向列表项添加密钥时会出现此警告。按照反应js文档 -
键帮助React识别哪些项目已更改,已添加或已添加 除去。键应该给予数组内的元素 元素稳定的身份:
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
选择密钥的最佳方法是使用唯一标识的字符串 兄弟姐妹中的一个列表项。大多数情况下,你会使用你的ID 数据作为键:
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
当您没有渲染项目的稳定ID时,您可以使用 项目索引作为关键作为最后的手段
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
答案 6 :(得分:4)
我通过向renderSeparator组件添加属性来修复它,代码在这里:
_renderSeparator(sectionID,rowID){
return (
<View style={styles.separatorLine} key={"sectionID_"+sectionID+"_rowID_"+rowID}></View>
);
}
此警告的关键字是“唯一”,sectionID + rowID在ListView中返回唯一值。
答案 7 :(得分:3)
我用来解决这个问题的具体代码是:
renderSeparator(sectionID, rowID, adjacentRowHighlighted) {
return (
<View style={styles.separator} key={`${sectionID}-${rowID}`}/>
)
}
我包含特定代码,因为您需要键是唯一的 - 即使对于分隔符也是如此。如果你做了类似的事情,例如,如果你把它设置为常量,你将会得到另一个关于重用密钥的恼人错误。如果您不了解JSX,那么构建JS回调以执行各个部分可能会非常痛苦。
在ListView上,显然附上了这个:
<ListView
style={styles.listview}
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}
renderSeparator={this.renderSeparator.bind(this)}
renderSectionHeader={this.renderSectionHeader.bind(this)}/>
感谢coldbuffet和Nader Dabit指出了这条道路。
答案 8 :(得分:3)
假设renderDetailItem方法具有following signature ...
(rowData, sectionID, rowID, highlightRow)
尝试这样做......
<TouchableHighlight key={rowID} underlayColor='#dddddd'>
答案 9 :(得分:1)
检查:key = undef !!!
您还会收到警告消息:
Each child in a list should have a unique "key" prop.
如果您的代码是完整的,但正确的话,
<MyComponent key={someValue} />
someValue未定义!!!请先检查一下。您可以节省几个小时。
答案 10 :(得分:1)
当您使用任何循环函数并在没有键的情况下渲染某些 HTML 元素时,即使您的父 div 有键,也会出现此错误,并且要解决此问题,您必须传递键。 >
请查看以下屏幕截图以更好地理解:
我已按照上述方式修复了此警告。
答案 11 :(得分:1)
如果你有一个空标签 <>
作为循环内结构的顶层,你会得到同样的错误:
return <select>
{Object.values(countries).map(c => {
return (<> // <== EMPTY TAG!
<option value={c.id}>{c.name}</option>
<States countryId={c.id} />
</>)
}
</select>
您可以使用 <React.Fragment>
的完整语法而不是短 <>
并将您的密钥添加到完整标签中:
import {Fragment} from 'react';
return <select>
{Object.values(countries).map(c => {
return (<Fragment key={c.id}> // You can also use <React.Fragment> without import
<option value={c.id}>{c.name}</option>
<States countryId={c.id} />
</Fragment>)
}
</select>
答案 12 :(得分:0)
似乎两个条件都得到满足,或许关键('联系')是问题
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') );
}
答案 13 :(得分:0)
这不能足够强调:
键仅在周围数组的上下文中有意义。
“例如,如果提取ListItem组件,则应将键保留在数组的
答案 14 :(得分:0)
这里是基于我的理解。希望它会有所帮助。作为后面的示例,它应该呈现所有组件的列表。每个组件的根标记都必须具有key
。它不必是唯一的。不能为key=0
,key='0'
等。它看起来像键是没用的。
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>),
];
}
答案 15 :(得分:0)
让我着迷这个问题的是,我认为需要将密钥应用于看起来像“真实”或DOM HTML元素,而不是我定义的JSX元素。
当然,在React中,我们正在使用虚拟DOM,因此我们定义的<MyElement>
的React JSX元素与看起来像<div>
这样的真实DOM HTML元素的元素一样重要。 / p>
这有意义吗?
答案 16 :(得分:0)
就我而言,我使用的是语义UI React“卡”视图。将密钥添加到所构造的每张卡后,警告就会消失,例如:
return (
<Card fluid key={'message-results-card'}>
...
</Card>
)
答案 17 :(得分:0)
这对我有用。
<View>
{
array.map((element, index) => {
return(
<React.Fragment key= {`arrayElement${index}`}>
{element}
</React.Fragment>
);
})
}
</View>
答案 18 :(得分:-1)
如果您在React应用程序中使用<Fade in>
元素,请同时在其中添加key={}
属性,否则控制台中将出现错误。