警告:数组或迭代器中的每个子代都应具有唯一的“键”道具。检查`ListView`的渲染方法


101

我使用ReactNative为iOS和android构建了一个带有的应用ListView。当使用有效的数据源填充listview时,屏幕底部将显示以下警告:

警告:数组或迭代器中的每个子代都应具有唯一的“键”道具。检查的渲染方法ListView

此警告的目的是什么?消息后,它们链接到此页面,在此页面上讨论了完整的不同内容,这些内容与react native无关,而与基于Web的reactjs有关。

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

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

一切正常,一切正常,除了警告似乎对我毫无意义。

向我的“ DetailItem”类添加密钥属性无法解决问题。

这是由于“ 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: '' } ] },

就像一个键一样,每个记录都有一个key属性。该警告仍然存在。


1
您很可能DetailItem需要钥匙。如果它们已经具有唯一键,则需要显示其他渲染方法(renderHeader, renderDetailItem, renderSeparator)。它们运行良好,并且可以预期,直到以某种方式修改数据源(例如,删除了行),此时,当它们没有唯一标识符时,React将不知道如何处理它们。
Pete TNT

“键”是什么意思?一个叫做“钥匙”的财产?
删除


它没有解决它。我在数据结构中添加了一个关键属性,并使用更详细的数据更新了原始问题。列出产生数据源的纯数据,每条记录都有一个键。此警告仍然存在。
删除

它也可能来自其他渲染方法(renderHeader,renderDetailItem,renderSeparator)
Pete TNT

Answers:


93

我有一段时间与您完全一样的问题,在查看了上述建议之后,我终于解决了该问题。

事实证明(至少无论如何对我来说),我需要为要从renderSeparator方法返回的组件提供一个键(称为“键”的道具)。将键添加到我的renderRow或renderSectionHeader并没有做任何事情,但是将其添加到renderSeparator会使警告消失。

希望能有所帮助。


就我而言,我只是删除了renderSeparator并将<Separator>移到了renderRow返回值的主体中。
boatcoder'Mar

对于SectionList,同样的事情,必须显式地为每个属性添加一个具有名称的属性,item以使RN满意。
LeOn-Han Li

1
在阅读本文之前,我浪费了大约8个小时来追踪我认为是JSON数据问题的地方。如果有堆栈溢出:taco:我给你一个!
hoekma '18

76

您需要提供一个密钥

如果您具有key属性,请尝试在ListView行中执行此操作:

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

如果不是,请尝试仅将该项添加为键:

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

1
我更喜欢这个答案,因为它有代码,所以我可以复制XD
Jovylle Bermudez,


21

从以下位置更改代码:

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

然后解决。


13

在列表的渲染根组件中添加一个道具“键”。

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

6

如果您未在列表项中添加键,则会出现此警告。根据react js Docs-

按键可帮助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>
);

4

我通过向renderSeparator组件添加属性来修复它,代码在这里:

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

该警告的关键字是“唯一”,sectionID + rowID在ListView中返回唯一值。


4

检查:键=未定义!!!

您还会收到警告消息:

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

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

<MyComponent key={someValue} />

someValue未定义!!!请先检查一下。您可以节省时间。


3

假设renderDetailItem方法具有以下签名...

(rowData, sectionID, rowID, highlightRow) 

试试这个...

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

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指出了我的这条路。


2

这是基于我的理解。希望它会有所帮助。作为后面的示例,它应该呈现任何组件的列表。每个组件的根标签都必须有一个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>),
    ];
}

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

不,联系不是关键。在这之间,我向数据结构添加了一个称为“键”的不动产,并通过传递更详细的数据来更新我的问题。没有帮助。警告仍然存在。
删除


0

使这个问题困扰我的是,我认为需要将密钥应用于看起来像“真实”或DOM HTML元素(而不是我定义的JSX元素)。

当然,在React中,我们正在使用虚拟DOM,因此我们定义的React JSX元素<MyElement>对它的重要性与看起来像真正的DOM HTML元素(如)一样重要<div>

那有意义吗?


0

就我而言,我使用的是语义UI React“ Card”视图。将密钥添加到所构造的每张卡后,警告就会消失,例如:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.