ChatGPT解决这个技术问题 Extra ChatGPT

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

我使用 ReactNative 为 iOS 和 android 构建了一个带有 ListView 的应用程序。使用有效数据源填充列表视图时,屏幕底部会打印以下警告:

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

这个警告的目的是什么?在消息之后他们链接到 this page,其中讨论了与 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”-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: '' } ] },

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

您的DetailItem很可能需要拥有密钥。如果它们已经具有唯一键,则需要显示其他渲染方法 (renderHeader, renderDetailItem, renderSeparator)。在数据源以某种方式被修改(例如,行被删除)之前,它们工作得很好并且可以预期,此时当它们没有唯一标识符时,React 将不知道如何处理它们。
“钥匙”是什么意思?一个名为“key”的属性?
它没有解决它。我在我的数据结构中添加了一个关键属性,并使用更详细的数据更新了原始问题。列出到 DataSource 的普通数据,每条记录都有一个键。这个警告仍然存在。
它也可能来自其他渲染方法(renderHeader、renderDetailItem、renderSeparator)

c
coldbuffet

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

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

希望有帮助。


在我的例子中,我只是删除了 renderSeparator 并将我的 移到了 renderRow 返回值的主体中。
SectionList 也是如此,必须为每个 item 显式添加一个名为 key 的属性,以使 RN 满意。
在阅读本文之前,我浪费了大约 8 个小时来追踪我认为我的 JSON 数据存在的问题。如果有堆栈溢出 :taco: 我会给你一个!
此外,如果您已经使用了 key 道具并且仍然收到此警告,请确保 key 道具位于地图的 OUTERMOST 元素上。
N
Nader Dabit

您需要提供密钥。

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

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

如果没有,请尝试将项目添加为键:

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

我更喜欢这个答案,因为它有代码,所以我可以复制 XD
这个答案有点改变了我对语言的理解。我特别认为我不能这样做,所以我不确定如何进行。现在我明白了看起来 HTML 的代码只是另一种语法,它不是要呈现的内容,它只是更容易阅读。
A
Agu Dondo

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

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

当数组更改时,这可能不起作用。这个答案用一个例子来解释它:stackoverflow.com/a/43892905/960857
D
David

更改您的代码:

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

然后解决了。


S
Shujat Munawar

向列表的渲染根组件添加一个 prop 'key'。

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

D
David Schumann

当您没有向列表项添加键时,会出现此警告。根据 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>
);

G
Gerd

检查:key = undef !!!

您还收到警告消息:

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

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

<MyComponent key={someValue} />

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


D
Dzmitry Kulahin

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

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>

这个解决方案对我有用!
D
David Schumann

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

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

这个警告的关键词是“唯一”,sectionID + rowID 返回ListView中的唯一值。


D
David Schumann

假设 renderDetailItem 方法具有 following signature...

(rowData, sectionID, rowID, highlightRow) 

尝试这样做...

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

D
David Schumann

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

  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,他们为我指明了这条道路。


c
caot

这里是基于我的理解。希望它会有所帮助。它应该呈现任何组件的列表作为后面的示例。每个组件的根标记都需要有一个 key。它不必是唯一的。不能是key=0key='0'等。看来key没用了。

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

D
David Schumann

似乎两个条件都满足了,也许 key('contact') 是问题

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

不,联系不是关键。在这期间,我在我的数据结构中添加了一个名为“key”的真实属性,并更新了我的问题,传递了更详细的数据。没有什么帮助。警告仍然存在。
D
Day Davis Waterbury

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

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

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


R
Ross Attrill

让我在这个问题上绊倒的事情是,我认为需要一个键应用于看起来像“真实”或 DOM HTML 元素,而不是我定义的 JSX 元素。

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

那有意义吗?


这是有道理的,但不是全部答案。仅仅因为您向 React 抱怨的元素添加 key 并不意味着错误会消失。我准备放弃并用 CLI 工具替换我的 WIP Web 仪表板。
M
Michael Bordash

就我而言,我使用的是 Semantic UI React "Card" 视图。一旦我为我构建的每张卡片添加了一个密钥,警告就消失了,例如:

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

S
Sahil Ralkar

当您使用任何循环函数并在没有键的情况下渲染某些 HTML 元素时,即使您的父 div 有键,也会出现此错误,并且要解决此问题,您必须传递键。

请检查以下屏幕截图以更好地理解:

https://i.stack.imgur.com/hYZZU.png

我已按照上述方式修复了此警告。


您如何准确确定哪些元素需要键?我遇到了同样的错误,并且有问题的元素非常复杂。无论我在哪里添加密钥,错误仍然存在!
M
Manil Malla

这对我有用。

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

这会抑制警告,但数组索引不是键的好选择。
c
codeepic

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


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅