警告: 数组或迭代器中的每个子元素都应该有一个唯一的“键”道具。请检查“ ListView”的呈现方法

我使用 反应原住民为 iOS 和使用 ListView的 Android 开发了一个应用程序。使用有效数据源填充列表视图时,将在屏幕底部显示以下警告:

警告: 数组或迭代器中的每个子级都应该有一个唯一的“键” prop. Check the render method of 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}
/>


);
}

我的数据源由以下内容组成:

    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)
});

And the ListView-Rows are rendered with stuff like:

        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>
);

一切正常运转,正如预期的那样,除了那个在我看来完全是胡说八道的警告。

给我的“ DetailItem”添加一个 key-property-Class 并没有解决这个问题。

This is, what really will be passed to the ListView as a result of "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: 'xxxxxxxxx@hotmail.com',
I/ReactNativeJS( 1293):           headline: 'Email',
I/ReactNativeJS( 1293):           icon: 'fontawesome|envelope' },
I/ReactNativeJS( 1293):         { key: 6, type: 'moreInfo', text: '', headline: '', icon: '' } ] },

正如一个键所见,每个记录都有一个键属性。警告仍然存在。

302380 次浏览

似乎这两个条件都得到了满足,也许关键(“接触”)是问题所在

 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') );
}

你需要提供一个 钥匙

如果您有一个键属性,请尝试在 ListView 行中执行此操作:

<TouchableHighlight key={item.key} underlayColor='#dddddd'>

如果没有,尝试只添加项目作为关键:

<TouchableHighlight key={item} underlayColor='#dddddd'>

假设 renderDetailItem 方法具有 跟随签名..。

(rowData, sectionID, rowID, highlightRow)

试试这样..。

<TouchableHighlight key={rowID} underlayColor='#dddddd'>

我和你一样有 没错的问题已经有一段时间了,在看了上面的一些建议之后,我终于解决了这个问题。

事实证明(至少对我来说是这样) ,我需要为从 renderMolecular ator 方法返回的组件提供一个键(一个名为“ key”的道具)。将键添加到 renderRow 或 renderSectionHeader 没有做任何事情,但是将它添加到 renderMolecular ator 使警告消失。

我用来解决这个问题的具体代码是:

  renderSeparator(sectionID, rowID, adjacentRowHighlighted) {
return (
<View style={styles.separator} key={`${sectionID}-${rowID}`}/>
)
}

I'm including the specific code because you need the keys to be unique--even for separators. If you do something similar e.g., if you set this to a constant, you will just get another annoying error about reuse of keys. If you don't know JSX, constructing the callback to JS to execute the various parts can be quite a pain.

在列表视图中,显然要附上这个:

<ListView
style={styles.listview}
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}
renderSeparator={this.renderSeparator.bind(this)}
renderSectionHeader={this.renderSectionHeader.bind(this)}/>

Credit to coldbuffet and Nader Dabit who pointed me down this path.

我通过向 renderMolecular ator Component 添加一个属性修复了这个问题,代码如下:

_renderSeparator(sectionID,rowID){
return (
<View style={styles.separatorLine} key={"sectionID_"+sectionID+"_rowID_"+rowID}></View>
);
}

此警告的关键词是“ only”,sectionID + rowID 在 ListView 中返回一个惟一值。

Change your code from:

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>
);
}

然后解决了。

您还可以使用迭代计数(i)作为 key:

render() {
return (
<ol>
{this.props.results.map((result, i) => (
<li key={i}>{result.text}</li>
))}
</ol>
);
}

当您没有向列表项添加键时,会出现此警告

键帮助 React 确定哪些项目已经更改、添加或正在更改 键应该给数组中的元素 元素一个稳定的身份:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);

选择键的最佳方法是使用唯一标识的字符串 a list item among its siblings. Most often you would use IDs from your 数据作为键:

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>
);

向列表的呈现根组件添加一个道具“键”。

<ScrollView>
<List>
{this.state.nationalities.map((prop, key) => {
return (
<ListItem key={key}>
<Text>{prop.name}</Text>
</ListItem>
);
})}
</List>
</ScrollView>

如果您正在将 <Fade in>元素用于一个反应应用程序,请在其中添加 key={}属性,否则您将在控制台中看到一个错误。

检查: key = undef! ! !

你还收到了警告信息:

Each child in a list should have a unique "key" prop.

如果您的代码是完全正确的,但如果

<MyComponent key={someValue} />

Some Value 是未定义的! ! ! 请先检查这个。您可以节省时间。

这一点怎么强调都不为过:

键只在周围数组 的上下文中有意义。

“例如,如果提取 ListItem 组件,则应该将键保留在数组中的 < ListItem/> 元素上,而不是保留在 ListItem 本身的 < li > 元素上。”—— https://reactjs.org/docs/lists-and-keys.html#extracting-components-with-keys

这是基于我的理解。希望能有帮助。它应该呈现任何组件的列表作为后面的示例。每个组件的根标记都需要一个 key。不一定非得是独一无二的。它不能是 key=0key='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>),
];
}

让我在这个问题上犯错误的是,我认为需要将一个键应用于看起来像“ real”或 DOM HTML 元素的内容,而不是我定义的 JSX 元素。

当然,使用 React 时,我们使用的是一个虚拟 DOM,因此我们定义的 React JSX 元素对于它来说与看起来像真正的 DOM HTML 元素(如 <div>)的元素一样重要。

这说得通吗?

在我的例子中,我使用的是语义 UI React“ Card”视图。一旦我在我构建的每张卡片上添加了一个密钥,警告就会消失,例如:

return (
<Card fluid key={'message-results-card'}>
...
</Card>
)

当您使用任何循环函数并在没有密钥的情况下呈现某些 HTML 元素时,即使您的父 div 具有密钥,也会出现此错误,要修复此错误,您必须传递密钥。

请查看下面的截图,以便更好地理解:

check the selected key and added in for each loop

我已经按照上面提到的方法修复了这个警告。

如果在循环中使用空标记 <>作为结构的顶层,则会得到相同的错误:

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>

这招对我很管用。

<View>
{
array.map((element, index) => {
return(
<React.Fragment key= {`arrayElement${index}`}>
{element}
</React.Fragment>
);
})
}
</View>