IOSとAndroidの両方で、ReactNativeを使用して ListView
を使用してアプリを作成しました。リストビューに有効なデータソースを入力すると、画面の下部に次の警告が表示されます。
警告:配列またはイテレータのそれぞれの子は、一意の「キー」プロップを持つべきです。
ListView
のレンダリング方法を確認してください。
この警告の目的は何ですか?メッセージの後、彼らは このページ にリンクします。ここでは、完全に異なることが議論されています。
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"クラスにキープロパティを追加しても問題は解決しませんでした。
これは、「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: '[email protected]',
I/ReactNativeJS( 1293): headline: 'Email',
I/ReactNativeJS( 1293): icon: 'fontawesome|envelope' },
I/ReactNativeJS( 1293): { key: 6, type: 'moreInfo', text: '', headline: '', icon: '' } ] },
見てのとおり、各レコードにはキープロパティがあります。警告はまだ存在します。
私は正確にしばらくの間あなたと同じ問題を抱えていました、そして上記の提案のいくつかを見た後、私はついに問題を解決しました。
結局のところ(少なくとも私にとっては)、私は私のrenderSeparatorメソッドから返すコンポーネントにキー( 'key'と呼ばれるプロップ)を供給する必要がありました。私のrenderRowやrenderSectionHeaderにキーを追加しても何もしませんでしたが、それをrenderSeparatorに追加しても警告は消えました。
それが役立つことを願っています。
あなたはkeyを提供する必要があります。
キープロパティがある場合は、これをListView Rowsで試してください。
<TouchableHighlight key={item.key} underlayColor='#dddddd'>
そうでない場合は、キーとしてアイテムを追加してみてください。
<TouchableHighlight key={item} underlayColor='#dddddd'>
繰り返し回数(i)をkey
として使用することもできます。
render() {
return (
<ol>
{this.props.results.map((result, i) => (
<li key={i}>{result.text}</li>
))}
</ol>
);
}
コードを以下から変更してください。
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>
);
}
それから解決した。
リストのレンダリングルートコンポーネントにプロップ 'key'を追加します。
<ScrollView>
<List>
{this.state.nationalities.map((prop, key) => {
return (
<ListItem key={key}>
<Text>{prop.name}</Text>
</ListItem>
);
})}
</List>
</ScrollView>
この警告はあなたがあなたのリストアイテムにキーを追加していないときに来ます。
キーは、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>
);
RenderSeparatorコンポーネントにプロパティを追加して修正しました。コードは次のとおりです。
_renderSeparator(sectionID,rowID){
return (
<View style={styles.separatorLine} key={"sectionID_"+sectionID+"_rowID_"+rowID}></View>
);
}
この警告のキーワードは "unique"で、sectionID + rowIDはListView内で一意の値を返します。
RenderDetailItemメソッドに 次のシグネチャ ...があるとします。
(rowData, sectionID, rowID, highlightRow)
これをやってみてください...
<TouchableHighlight key={rowID} underlayColor='#dddddd'>
これを修正するために使用した特定のコードは次のとおりです。
renderSeparator(sectionID, rowID, adjacentRowHighlighted) {
return (
<View style={styles.separator} key={`${sectionID}-${rowID}`}/>
)
}
あなたがキーをユニークにする必要があるので、私は特定のコードを含めます - たとえセパレータのためでさえ。たとえばこれを定数に設定した場合など、同様のことをした場合は、キーの再利用について別の迷惑なエラーが発生します。 JSXがわからない場合は、さまざまな部分を実行するためにJSへのコールバックを作成するのは非常に面倒です。
そして、リストビューでは、明らかにこれを添付します。
<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のおかげです。
チェック:キー= undef !!!
警告メッセージも表示されます。
Each child in a list should have a unique "key" prop.
あなたのコードが完全であれば
<MyComponent key={someValue} />
someValueは未定義です!!!まずこれを確認してください。あなたは時間を節約することができます。
両方の条件が満たされているように見えますが、おそらく重要なのは(「連絡先」)問題です。
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') );
}
これは十分強調することはできません。
キーは周囲の配列のコンテキストでのみ意味があります。
「たとえば、ListItemコンポーネントを抽出する場合は、ListItem自体の<li>要素ではなく、配列の<ListItem />要素にキーを保持する必要があります。」 - https://reactjs.org/docs/lists-and-keys.html#extracting-components-with-keys