चेतावनी: एक सरणी या पुनरावृत्त में प्रत्येक बच्चे के पास एक अद्वितीय "कुंजी" प्रोप होना चाहिए। `ListView` की रेंडर विधि की जाँच करें


101

मैंने iOS और Android दोनों के लिए ReactNative के साथ एक ऐप बनाया है ListView। मान्य डेटा स्रोत के साथ सूची को पॉप्युलेट करते समय, निम्न चेतावनी स्क्रीन के नीचे मुद्रित होती है:

चेतावनी: एक सरणी या पुनरावृत्त में प्रत्येक बच्चे के पास एक अद्वितीय "कुंजी" प्रोप होना चाहिए। की रेंडर विधि की जाँच करें 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)
    });

और सूची दृश्य-पंक्तियों को सामान की तरह प्रस्तुत किया गया है:

        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: '' } ] },

एक कुंजी के रूप में, प्रत्येक रिकॉर्ड में एक महत्वपूर्ण संपत्ति होती है। चेतावनी अभी भी मौजूद है।


1
सबसे अधिक संभावना है कि आपके DetailItemपास कुंजी होनी चाहिए। यदि उनके पास पहले से ही अद्वितीय चाबियाँ हैं, तो आपको अन्य रेंडर विधियों ( renderHeader, renderDetailItem, renderSeparator) को दिखाने की आवश्यकता है । वे ठीक काम कर रहे हैं और उम्मीद की जाती है जब तक कि किसी स्रोत में डेटा स्रोत को संशोधित नहीं किया जाता है (उदाहरण के लिए पंक्तियों को हटा दिया जाता है), जिस बिंदु पर रिएक्ट को पता नहीं चलेगा कि उनके साथ क्या करना है जब उनके पास एक विशिष्ट पहचानकर्ता नहीं है।
पीट टीएनटी

"चाबियाँ" के साथ आपका क्या मतलब है? एक संपत्ति जिसे "कुंजी" कहा जाता है?
हटाएं


यह इसे हल नहीं करता है। मैंने अपने डेटा संरचना में एक महत्वपूर्ण गुण जोड़ा और मूल प्रश्न को और अधिक डेटा से अपडेट किया। सादे डेटा को सूचीबद्ध करना, जिसके परिणामस्वरूप डेटा स्रोत है, प्रत्येक रिकॉर्ड के लिए एक कुंजी है। यह चेतावनी बनी हुई है।
हटाएं

यह अन्य रेंडर तरीकों से भी आ सकता है (रेंडरहेडर, रेंडरडेलटैम, रेंडरसेप्टर)
टीएनटी

जवाबों:


93

मैं बिल्कुल था अब थोड़ी देर के लिए आप के रूप में एक ही समस्या है, और ऊपर दिए गए सुझावों में से कुछ देखने के बाद, मैं अंत में समस्या हल हो।

यह पता चला है (कम से कम मेरे लिए वैसे भी), मुझे उस घटक को एक कुंजी ('कुंजी' कहा जाता है) की आपूर्ति करने की आवश्यकता है जो मैं अपने रेंडरसेपरेटर विधि से वापस आ रहा हूं। मेरे रेंडर करने के लिए एक कुंजी जोड़ना या रेंडरसेन्हैडर कुछ भी नहीं करता है, लेकिन रेंडरसेटर में इसे जोड़ने से चेतावनी दूर हो जाती है।

उम्मीद है की वो मदद करदे।


मेरे मामले में, मैंने बस रेंडरसेप्टर को हटा दिया और रेंडर रिटर्न वैल्यू के बॉडी में मेरे <सेपरेटर> को स्थानांतरित कर दिया।
नाविक

यहाँ के लिए एक ही बात है SectionList, स्पष्ट रूप से आरएन को खुश करने के लिए प्रत्येक के लिए नाम कुंजी के साथ एक संपत्ति जोड़ना है item
लियोन - हान ली

1
इसे पढ़ने से पहले मैंने लगभग 8 घंटे बर्बाद किए, जो मुझे लगा कि मेरे JSON डेटा के साथ समस्या है। अगर वहाँ एक ढेर अतिप्रवाह था: टैको: मैं तुम्हें एक दे देंगे!
होकेमा

76

आपको एक कुंजी प्रदान करने की आवश्यकता है ।

यदि आपके पास कोई महत्वपूर्ण संपत्ति है, तो अपने ListView Rows में ऐसा करने का प्रयास करें:

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

यदि नहीं, तो केवल कुंजी के रूप में आइटम जोड़ने का प्रयास करें:

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

1
मुझे यह उत्तर अधिक पसंद है, क्योंकि इसमें कोड है इसलिए मैं XD की प्रतिलिपि बना सकता
हूं

34

आप पुनरावृति गणना (i) का उपयोग इस रूप में भी कर सकते हैं key:

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

2
सरणी बदलने पर यह काम नहीं कर सकता है। यह उत्तर इसे एक उदाहरण से समझाता है: stackoverflow.com/a/43892905/960857
क्रिस

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

यह चेतावनी तब आती है जब आप अपनी सूची आइटम्स में एक कुंजी नहीं जोड़ते हैं। प्रति प्रतिक्रिया js डॉक्स के अनुसार -

कुंजियाँ प्रतिक्रिया को पहचानने में मदद करती हैं कि कौन से आइटम बदल गए हैं, जोड़े गए हैं, या हटा दिए गए हैं। तत्वों को एक स्थिर पहचान देने के लिए सरणी के अंदर तत्वों को कुंजी दी जानी चाहिए:

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

कुंजी चुनने का सबसे अच्छा तरीका एक स्ट्रिंग का उपयोग करना है जो विशिष्ट रूप से अपने भाई-बहनों के बीच एक सूची आइटम की पहचान करता है। अक्सर आप कुंजी के रूप में अपने डेटा से आईडी का उपयोग करेंगे:

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

जब आपके पास प्रदान की गई वस्तुओं के लिए स्थिर आईडी नहीं है, तो आप अंतिम उपाय के रूप में कुंजी के रूप में आइटम इंडेक्स का उपयोग कर सकते हैं

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

4

मैंने इसे एक संपत्ति जोड़कर तय किया है रेंडरसेपरेटर घटक, कोड यहाँ है:

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

इस चेतावनी के मुख्य शब्द "अद्वितीय" हैं, सेक्शनआईडी + रोआईडी लिस्ट व्यू में एक अद्वितीय मान लौटाता है।


4

जाँच करें: कुंजी = अपराजित !!!

आपको चेतावनी संदेश भी मिला:

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}`}/>
    )
  }

मैं विशिष्ट कोड शामिल कर रहा हूं क्योंकि आपको विशिष्ट होने के लिए कुंजी की आवश्यकता है - यहां तक ​​कि विभाजकों के लिए भी। यदि आप कुछ ऐसा ही करते हैं, जैसे यदि आप इसे स्थिरांक पर सेट करते हैं, तो आपको कुंजी के पुन: उपयोग के बारे में एक और कष्टप्रद त्रुटि मिलेगी। यदि आप जेएसएक्स को नहीं जानते हैं, तो विभिन्न भागों को निष्पादित करने के लिए जेएस को कॉलबैक का निर्माण करना काफी दर्द हो सकता है।

और ListView पर, जाहिर है यह संलग्न:

<ListView
  style={styles.listview}
  dataSource={this.state.dataSource}
  renderRow={this.renderRow.bind(this)}
  renderSeparator={this.renderSeparator.bind(this)}
  renderSectionHeader={this.renderSectionHeader.bind(this)}/>

कोल्डबफेट और नादेर दबित को श्रेय दिया जिन्होंने मुझे इस रास्ते पर जाने का इशारा किया।


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 घटक को निकालते हैं, तो आपको सूची में <li> तत्व की बजाय <ListItem /> तत्वों को कुंजी में रखना चाहिए।" - https://reactjs.org/docs/lists-and-keys.html#extracting-compenders-with-keys


0

इस समस्या पर मुझे जिस चीज़ ने परेशान किया वह यह था कि मैंने सोचा था कि जेएसएक्स तत्वों के विपरीत 'वास्तविक' या डोम एचटीएमएल तत्वों की तरह लागू होने वाली कुंजी की आवश्यकता है जिसे मैंने परिभाषित किया है।

बेशक रिएक्ट के साथ हम एक आभासी डोम के साथ काम कर रहे हैं, इसलिए रिएक्ट JSX तत्वों को हम परिभाषित करते <MyElement>हैं, जो वास्तविक डोम एचटीएमएल तत्वों जैसे दिखने वाले तत्वों की तरह ही महत्वपूर्ण हैं <div>

क्या इसका कोई मतलब है?


0

मेरे मामले में, मैं शब्दार्थ यूआई प्रतिक्रिया "कार्ड" दृश्य का उपयोग कर रहा था। एक बार मैंने अपने द्वारा बनाए गए प्रत्येक कार्ड में एक कुंजी जोड़ दी, उदाहरण के लिए, चेतावनी चली गई:

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

-1

यदि आप <Fade in>प्रतिक्रिया एप्लिकेशन के लिए तत्व का उपयोग कर रहे हैं तो कृपया उसमें key={}विशेषता जोड़ें या आप कंसोल में एक त्रुटि देखेंगे।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.