简体   繁体   English

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

[英]Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `ListView`

I built an app with ReactNative both for iOS and android with a ListView .我使用ReactNative为 iOS 和 android 构建了一个带有ListView的应用程序。 When populating the listview with a valid datasource, the following warning is printed at the bottom of the screen:使用有效数据源填充列表视图时,屏幕底部会打印以下警告:

Warning: Each child in an array or iterator should have a unique "key" prop.警告:数组或迭代器中的每个孩子都应该有一个唯一的“键”道具。 Check the render method of ListView .检查ListView的渲染方法。

What is the purpose of this warning?这个警告的目的是什么? After the message they link to this page , where complete different things are discussed which have nothing to do with react native, but with web based reactjs.在他们链接到此页面的消息之后,讨论了完全不同的事情,这些事情与本机反应无关,但与基于 reactjs 的 web 无关。

My ListView is built with those statements:我的 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}
            />

    );
}

My DataSource consists of something like:我的数据源包含以下内容:

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

Everything works fine and as expected, except the warning which seems to be complete nonsense to me.一切正常,正如预期的那样,除了对我来说似乎完全是胡说八道的警告。

Adding a key-property to my "DetailItem"-Class didn't solve the issue.将关键属性添加到我的“DetailItem”类并没有解决问题。

This is, what really will be passed to the ListView as a result of "cloneWithRows":这是,作为“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: '' } ] },

As one key see, each record has a key property.正如一个键所见,每条记录都有一个键属性。 The warning still exists.警告仍然存在。

I've had exactly the same problem as you for a while now, and after looking at some of the suggestions above, I finally solved the problem.我和你有一段时间完全一样的问题,看了上面的一些建议后,我终于解决了这个问题。

It turns out (at least for me anyway), I needed to supply a key (a prop called 'key') to the component I am returning from my renderSeparator method.事实证明(至少对我而言),我需要为从我的 renderSeparator 方法返回的组件提供一个密钥(一个名为“密钥”的道具)。 Adding a key to my renderRow or renderSectionHeader didn't do anything, but adding it to renderSeparator made the warning go away.向我的 renderRow 或 renderSectionHeader 添加一个键没有做任何事情,但是将它添加到 renderSeparator 使警告消失了。

Hope that helps.希望有帮助。

You need to provide a key .您需要提供密钥

Try doing this in your ListView Rows if you have a key property:如果您有关键属性,请尝试在您的 ListView Rows 中执行此操作:

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

If not, try just adding the item as the key:如果没有,请尝试将项目添加为键:

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

You can also use the iteration count (i) as the key :您还可以使用迭代计数 (i) 作为key

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

Change your code from:更改您的代码:

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

To:至:

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

Then solved.然后解决了。

Add a prop 'key' to the rendering root component of the list.向列表的渲染根组件添加一个 prop 'key'。

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

This warning comes when you don't add a key to your list items.As per react js Docs -当您没有向列表项添加键时,会出现此警告。根据 react js Docs -

Keys help React identify which items have changed, are added, or are removed.键帮助 React 识别哪些项目已更改、添加或删除。 Keys should be given to the elements inside the array to give the elements a stable identity:应为数组内的元素提供键,以使元素具有稳定的标识:

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

The best way to pick a key is to use a string that uniquely identifies a list item among its siblings.选择键的最佳方法是使用一个字符串,该字符串在其兄弟项中唯一标识一个列表项。 Most often you would use IDs from your data as keys:大多数情况下,您会使用数据中的 ID 作为键:

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

When you don't have stable IDs for rendered items, you may use the item index as a key as a last resort当您没有用于渲染项目的稳定 ID 时,您可以使用项目索引作为键作为最后的手段

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

Check: key = undef !!!检查:key = undef !!!

You got also the warn message:您还收到警告消息:

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

if your code is complete right, but if on如果您的代码完整正确,但如果打开

<MyComponent key={someValue} />

someValue is undefined!!! someValue 未定义!!! Please check this first.请先检查一下。 You can save hours.您可以节省数小时。

You are getting the same error if you have an empty tag <> as the top level of your structure inside a loop:如果你有一个空标签<>作为循环内结构的顶层,你会得到同样的错误:

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

You can use full syntax of <React.Fragment> instead of short <> and add your key to the full tag:您可以使用<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>

I fixed it by add a property to renderSeparator Component,the code is here:我通过向 renderSeparator 组件添加属性来修复它,代码在这里:

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

The key words of this warning is "unique", sectionID + rowID return a unique value in ListView.这个警告的关键词是“唯一”,sectionID + rowID 返回ListView中的唯一值。

Assuming the renderDetailItem method has the following signature ...假设 renderDetailItem 方法具有以下签名...

(rowData, sectionID, rowID, highlightRow) 

Try doing this...尝试这样做...

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

The specific code I used to fix this was:我用来解决这个问题的具体代码是:

  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 eg, 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.如果您不了解 JSX,构建 JS 的回调来执行各个部分可能会非常痛苦。

And on the ListView, obviously attaching this:在 ListView 上,显然附上了这个:

<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.感谢 Coldbuffet 和 Nader Dabit,他们为我指明了这条道路。

Here is based on my understanding.这里是基于我的理解。 Hopefully it's helpful.希望它会有所帮助。 It's supposed to render a list of any components as the example behind.它应该呈现任何组件的列表作为后面的示例。 The root tag of each component needs to have a key .每个组件的根标签都需要有一个key It doesn't have to be unique.它不必是唯一的。 It cannot be key=0 , key='0' , etc. It looks the key is useless.它不能是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>),
    ];
}

Seems like both the conditions are met, perhaps key('contact') is the issue似乎两个条件都满足了,也许 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') );
}

This cannot be emphasized enough:这一点怎么强调都不过分:

Keys only make sense in the context of the surrounding array .键仅在周围数组的上下文中才有意义

"For example, if you extract a ListItem component, you should keep the key on the <ListItem /> elements in the array rather than on the <li> element in the ListItem itself." “例如,如果您提取 ListItem 组件,则应将键保留在数组中的 <ListItem /> 元素上,而不是 ListItem 本身中的 <li> 元素上。” -- https://reactjs.org/docs/lists-and-keys.html#extracting-components-with-keys -- https://reactjs.org/docs/lists-and-keys.html#extracting-components-with-keys

The thing that tripped me up on this problem was that I thought that the need for a key applied to what looks like 'real' or DOM HTML elements as opposed to JSX elements that I have defined.让我在这个问题上绊倒的事情是,我认为需要一个键应用于看起来像“真实”或 DOM HTML 元素,而不是我定义的 JSX 元素。

Of course with React we are working with a virtual DOM so the React JSX elements we define <MyElement> are just as important to it as the elements that look like real DOM HTML elements like <div> .当然,在 React 中,我们使用的是虚拟 DOM,因此我们定义的 React JSX 元素<MyElement>与看起来像真实 DOM HTML 元素(如<div> )的元素一样重要。

Does that make sense?那有意义吗?

In my case, I was using the Semantic UI React "Card" view.就我而言,我使用的是 Semantic UI React "Card" 视图。 Once I added a key to each card I constructed, the warning went away, for example:一旦我为我构建的每张卡片添加了一个密钥,警告就消失了,例如:

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

This error comes when you are using any loop function and rendering some HTML element without a key even if your parent div has the key and to fix this you must have to pass the key.当您使用任何循环函数并渲染一些没有键的 HTML 元素时,即使您的父 div 有键,也会出现此错误,并且要解决此问题,您必须传递键。

Please check the following screenshot to understand better:请检查以下屏幕截图以更好地理解:

检查选定的键并为每个循环添加

I've fixed this warning following the above-mentioned way.我已按照上述方式修复了此警告。

This worked for me.这对我有用。

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM