警告:数组或迭代器中的每个子节点都应该具有唯一的"键"支柱.检查`ListView`的render方法

del*_*ete 77 listview facebook reactjs react-native

我内置有应用ReactNative无论是iOS和了Android 的ListView.使用有效数据源填充列表视图时,屏幕底部会显示以下警告:

警告:数组或迭代器中的每个子节点都应该具有唯一的"键"支柱.检查渲染方法ListView.

这个警告的目的是什么?在消息之后,它们链接到以下页面:https://fb.me/react-warning-keys,其中讨论了完全不同的内容,这些内容与本机反应无关,但与基于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}
            />

    );
}
Run Code Online (Sandbox Code Playgroud)

我的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)
    });
Run Code Online (Sandbox Code Playgroud)

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>
        );
Run Code Online (Sandbox Code Playgroud)

一切都很好,正如预期的那样,除了警告似乎对我来说完全无稽之谈.

向我的"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: '' } ] },
Run Code Online (Sandbox Code Playgroud)

一键看,每条记录都有一个关键属性.警告仍然存在.

col*_*fet 77

我有一段时间和你有完全相同的问题,在看了上面的一些建议后,我终于解决了这个问题.

事实证明(至少对我而言),我需要为我从renderSeparator方法返回的组件提供一个键(一个名为'key'的道具).向renderRow或renderSectionHeader添加一个键没有做任何事情,但是将它添加到renderSeparator会使警告消失.

希望有所帮助.

  • 在阅读本文之前,我浪费了大约 8 个小时来查找我认为 JSON 数据存在问题的地方。如果有堆栈溢出:taco:我会给你一个! (3认同)

Nad*_*bit 65

你需要提供一把钥匙.

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

<TouchableHighlight key={item.key} underlayColor='#dddddd'>
Run Code Online (Sandbox Code Playgroud)

如果没有,请尝试添加该项作为键:

<TouchableHighlight key={item} underlayColor='#dddddd'>
Run Code Online (Sandbox Code Playgroud)

  • 我更喜欢这个答案,因为它有代码,所以我可以复制XD (3认同)

Agu*_*ndo 31

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

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

  • 当阵列发生变化时,这可能不起作用.这个答案用一个例子解释了它:/sf/answers/3072503381/ (2认同)

Dmi*_*hin 24

<>如果循环内结构的顶层为空标记,您会收到相同的错误:

return <select>
    {Object.values(countries).map(c => {
        return (<>           {/*   <== EMPTY TAG!   */}
            <option value={c.id}>{c.name}</option>
            <States countryId={c.id} />
        </>)
    }
</select>
Run Code Online (Sandbox Code Playgroud)

您可以使用完整语法<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>
Run Code Online (Sandbox Code Playgroud)

  • 在react.native中工作就像做梦一样,非常感谢! (2认同)

小智 18

更改您的代码:

render() {
    return (
      <ol>
        {this.props.results.map((result) => (
          <li>{result.text}</li>
        ))}
      </ol>
    );
}
Run Code Online (Sandbox Code Playgroud)

至:

render() {
    return (
      <ol>
        {this.props.results.map((result) => (
          <li key={result.id}>{result.text}</li>
        ))}
      </ol>
    );
}
Run Code Online (Sandbox Code Playgroud)

然后解决了.


SHU*_*WAR 9

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

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


Jag*_*ati 6

当您没有向列表项添加密钥时会出现此警告.按照反应js文档 -

密钥帮助React识别哪些项目已更改,已添加或已删除.应该为数组内部的元素赋予键,以使元素具有稳定的标识:

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

选择密钥的最佳方法是使用在其兄弟姐妹中唯一标识列表项的字符串.大多数情况下,您会使用数据中的ID作为键:

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);
Run Code Online (Sandbox Code Playgroud)

如果渲染项目没有稳定的ID,则可以将项目索引用作关键字作为最后的手段

const todoItems = todos.map((todo, index) =>
  // Only do this if items have no stable IDs
  <li key={index}>
    {todo.text}
  </li>
);
Run Code Online (Sandbox Code Playgroud)


Ger*_*erd 6

检查:key = undef !!!

您还收到警告消息:

Each child in a list should have a unique "key" prop.
Run Code Online (Sandbox Code Playgroud)

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

<MyComponent key={someValue} />
Run Code Online (Sandbox Code Playgroud)

someValue 未定义!!!请先检查这个。您可以节省数小时。