คำเตือน: ลูกแต่ละคนในอาร์เรย์หรือตัววนซ้ำควรมี "คีย์" ที่ไม่ซ้ำ ตรวจสอบวิธีการแสดงผลของ "ListView"


105

ฉันสร้างแอพด้วยReactNativeทั้งสำหรับ iOS และ Android ด้วยไฟล์ListView. เมื่อเติมข้อมูลมุมมองรายการด้วยแหล่งข้อมูลที่ถูกต้องคำเตือนต่อไปนี้จะพิมพ์ที่ด้านล่างของหน้าจอ:

คำเตือน: ลูกแต่ละคนในอาร์เรย์หรือตัววนซ้ำควรมีเสา "คีย์" เฉพาะ ListViewตรวจสอบการแสดงผลของวิธีการ

คำเตือนนี้มีจุดประสงค์อะไร? หลังจากข้อความพวกเขาเชื่อมโยงไปยังหน้านี้ซึ่งจะมีการพูดคุยถึงสิ่งที่แตกต่างกันโดยสมบูรณ์ซึ่งไม่มีส่วนเกี่ยวข้องกับ react native แต่ใช้ reactjs บนเว็บ

My 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 ของฉันไม่ได้ช่วยแก้ปัญหานี้

นี่คือสิ่งที่จะส่งผ่านไปยัง ListView อันเป็นผลมาจาก "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: '' } ] },

ตามที่เห็นคีย์เดียวแต่ละระเบียนมีคุณสมบัติหลัก คำเตือนยังคงมีอยู่


1
เป็นไปได้มากว่าคุณDetailItemต้องมีกุญแจ หากมีคีย์ที่ไม่ซ้ำกันอยู่แล้วคุณต้องแสดงวิธีการแสดงผลอื่น ๆ ( renderHeader, renderDetailItem, renderSeparator) พวกเขาทำงานได้ดีและคาดหวังจนกว่าแหล่งข้อมูลจะถูกแก้ไขในบางครั้ง (เช่นแถวจะถูกลบออก) ณ จุดนั้น React จะไม่รู้ว่าจะทำอย่างไรกับพวกเขาเมื่อพวกเขาไม่มีตัวระบุที่ไม่ซ้ำกัน
Pete TNT

คุณหมายถึงอะไรกับ "กุญแจ"? คุณสมบัติที่เรียกว่า "กุญแจ"?
ลบ


มันไม่สามารถแก้ปัญหาได้ ฉันเพิ่มคุณสมบัติหลักในโครงสร้างข้อมูลของฉันและอัปเดตคำถามเดิมด้วยข้อมูลที่มีรายละเอียดมากขึ้น การแสดงรายการข้อมูลธรรมดาซึ่งส่งผลไปยังแหล่งข้อมูลมีคีย์ต่อแต่ละระเบียน คำเตือนนี้ยังคงอยู่
ลบ

อาจมาจากวิธีการเรนเดอร์อื่น ๆ ด้วย (renderHeader, renderDetailItem, renderSeparator)
Pete TNT

คำตอบ:


95

ฉันเคยว่าปัญหาที่เกิดขึ้นเช่นเดียวกับคุณสำหรับขณะนี้และหลังจากมองที่บางส่วนของข้อเสนอแนะดังกล่าวข้างต้นในที่สุดผมก็แก้ปัญหาได้

ปรากฎว่า (อย่างน้อยก็สำหรับฉันแล้ว) ฉันต้องจัดหาคีย์ (เสาที่เรียกว่า 'คีย์') ให้กับส่วนประกอบที่ฉันส่งคืนจากเมธอด renderSeparator การเพิ่มคีย์ใน renderRow หรือ renderSectionHeader ของฉันไม่ได้ทำอะไรเลย แต่การเพิ่มเข้าไปใน renderSeparator ทำให้คำเตือนหายไป

หวังว่าจะช่วยได้


ในกรณีของฉันฉันเพิ่งลบ renderSeparator และย้าย <Separator> ของฉันไปไว้ในเนื้อความของค่าส่งคืน renderRow
boatcoder

สิ่งเดียวกันที่นี่SectionListต้องเพิ่มคุณสมบัติที่มีคีย์ชื่ออย่างชัดเจนสำหรับแต่ละรายการitemเพื่อให้ RN มีความสุข
LeOn - Han Li

1
ก่อนที่จะอ่านสิ่งนี้ฉันเสียเวลาไปประมาณ 8 ชั่วโมงในการติดตามสิ่งที่ฉันคิดว่าเป็นปัญหากับข้อมูล JSON ของฉัน ถ้ามีสแต็กล้น: taco: ฉันจะให้คุณ!
hoekma

79

คุณจำเป็นต้องให้ความสำคัญ

ลองทำสิ่งนี้ใน ListView Rows ของคุณหากคุณมีคุณสมบัติหลัก:

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

หากไม่เป็นเช่นนั้นให้ลองเพิ่มรายการเป็นคีย์:

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

1
ฉันชอบคำตอบนี้มากกว่าเพราะมีรหัสดังนั้นฉันจึงสามารถคัดลอก XD ได้
Jovylle Bermudez

35

คุณยังสามารถใช้การนับการวนซ้ำ (i) เป็นkey:

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

2
สิ่งนี้อาจไม่ทำงานเมื่ออาร์เรย์เปลี่ยนไป คำตอบนี้อธิบายด้วยตัวอย่าง: stackoverflow.com/a/43892905/960857
Chris

22

เปลี่ยนรหัสของคุณจาก:

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

เพิ่ม 'คีย์' prop ในองค์ประกอบรูทการแสดงผลของรายการ

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

6

คำเตือนนี้เกิดขึ้นเมื่อคุณไม่ได้เพิ่มคีย์ให้กับรายการของคุณตามปฏิกิริยา js Docs -

คีย์ช่วยตอบสนองระบุว่ารายการใดมีการเปลี่ยนแปลงเพิ่มหรือถูกลบออก ควรกำหนดคีย์ให้กับองค์ประกอบภายในอาร์เรย์เพื่อให้องค์ประกอบมีเอกลักษณ์ที่มั่นคง:

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 Component รหัสอยู่ที่นี่:

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

คำสำคัญของคำเตือนนี้คือ "ไม่ซ้ำใคร" sectionID + rowID จะส่งคืนค่าที่ไม่ซ้ำกันใน ListView


4

ตรวจสอบ: key = undef !!!

คุณยังได้รับข้อความเตือน:

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

ถ้ารหัสของคุณสมบูรณ์ถูกต้อง แต่ถ้าเปิด

<MyComponent key={someValue} />

someValue ไม่ได้กำหนด !!! โปรดตรวจสอบสิ่งนี้ก่อน คุณสามารถประหยัดชั่วโมง



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=0, key='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

สิ่งนี้ไม่สามารถเน้นได้เพียงพอ:

คีย์มีความหมายเฉพาะในบริบทของอาร์เรย์รอบข้าง

"ตัวอย่างเช่นหากคุณแยกองค์ประกอบ ListItem คุณควรเก็บคีย์ไว้บนองค์ประกอบ <ListItem /> ในอาร์เรย์แทนที่จะอยู่ในองค์ประกอบ <li> ใน ListItem เอง" - https://reactjs.org/docs/lists-and-keys.html#extracting-components-with-keys


0

สิ่งที่ทำให้ฉันสะดุดกับปัญหานี้คือฉันคิดว่าความต้องการคีย์ที่ใช้กับองค์ประกอบ HTML ที่ดูเหมือน 'จริง' หรือ DOM ซึ่งตรงข้ามกับองค์ประกอบ JSX ที่ฉันได้กำหนดไว้

แน่นอนว่าด้วย React เรากำลังทำงานกับ DOM เสมือนดังนั้นองค์ประกอบ React JSX ที่เรากำหนด<MyElement>จึงมีความสำคัญพอ ๆ กับองค์ประกอบที่มีลักษณะเหมือนองค์ประกอบ DOM HTML ที่<div>แท้จริง

มันสมเหตุสมผลไหม


0

ในกรณีของฉันฉันใช้มุมมอง Semantic UI React "Card" เมื่อฉันเพิ่มคีย์ให้กับการ์ดแต่ละใบที่ฉันสร้างคำเตือนก็หายไปเช่น:

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

-1

หากคุณกำลังใช้<Fade in>องค์ประกอบสำหรับแอปพลิเคชันการตอบสนองโปรดเพิ่มkey={}แอตทริบิวต์ด้วยไม่เช่นนั้นคุณจะเห็นข้อผิดพลาดในคอนโซล

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.