Ich baue eine React-Komponente, die eine JSON-Datenquelle akzeptiert und eine sortierbare Tabelle erstellt.
Jeder der dynamischen Datenzeilen ist ein eindeutiger Schlüssel zugewiesen. Ich erhalte jedoch immer noch einen Fehler:
Jedes Kind in einem Array sollte eine eindeutige "Schlüssel" -Stütze haben.
Überprüfen Sie die Render-Methode von TableComponent.
Meine TableComponent
Render-Methode gibt Folgendes zurück:
<table>
<thead key="thead">
<TableHeader columns={columnNames}/>
</thead>
<tbody key="tbody">
{ rows }
</tbody>
</table>
Die TableHeader
-Komponente ist eine einzelne Zeile und es ist auch ein eindeutiger Schlüssel zugewiesen.
Jeder row
in rows
besteht aus einer Komponente mit einem eindeutigen Schlüssel:
<TableRowItem key={item.id} data={item} columns={columnNames}/>
Und der TableRowItem
sieht so aus:
var TableRowItem = React.createClass({
render: function() {
var td = function() {
return this.props.columns.map(function(c) {
return <td key={this.props.data[c]}>{this.props.data[c]}</td>;
}, this);
}.bind(this);
return (
<tr>{ td(this.props.item) }</tr>
)
}
});
Was verursacht den eindeutigen Propellerfehler?
Sie sollten jedem Kind sowie jedem Element innerhalb von Kindern einen Schlüssel hinzufügen.
Auf diese Weise kann React die minimale DOM-Änderung verarbeiten.
In Ihrem Code versucht jeder <TableRowItem key={item.id} data={item} columns={columnNames}/>
, einige untergeordnete Elemente ohne Schlüssel darzustellen.
Überprüfen Sie dieses Beispiel .
Versuchen Sie, den key={i}
aus dem <b></b>
-Element in den Divs zu entfernen (und überprüfen Sie die Konsole).
Wenn wir im Beispiel dem <b>
-Element keinen Schlüssel geben und wir only the object.city
aktualisieren möchten, muss React die gesamte Zeile gegenüber dem Element erneut rendern.
Hier ist der Code:
var data = [{name:'Jhon', age:28, city:'HO'},
{name:'Onhj', age:82, city:'HN'},
{name:'Nohj', age:41, city:'IT'}
];
var Hello = React.createClass({
render: function() {
var _data = this.props.info;
console.log(_data);
return(
<div>
{_data.map(function(object, i){
return <div className={"row"} key={i}>
{[ object.name ,
// remove the key
<b className="fosfo" key={i}> {object.city} </b> ,
object.age
]}
</div>;
})}
</div>
);
}
});
React.render(<Hello info={data} />, document.body);
Die Antwort, die von @Chris am Ende gepostet wird, geht weitaus detaillierter als diese Antwort. Bitte schauen Sie nach https://stackoverflow.com/a/43892905/2325522
Reagieren Sie Dokumentation über die Bedeutung von Schlüsseln beim Abgleich: Schlüssel
Vorsicht beim Durchlaufen von Arrays !!
Es ist ein verbreiteter Irrtum, dass die Verwendung des Index des Elements im Array eine akzeptable Methode ist, um den Fehler zu unterdrücken, mit dem Sie wahrscheinlich vertraut sind:
Each child in an array should have a unique "key" prop.
In vielen Fällen ist dies jedoch nicht der Fall! Dies ist Anti-Muster, das in einigen Situationen zu nerwünschtem Verhalten führen kann.
key
React verwendet die Requisite key
, um die Beziehung zwischen Komponente und DOM-Element zu verstehen, die dann für den - Abgleichsprozess verwendet wird. Es ist daher sehr wichtig, dass der Schlüssel immer bleibt eindeutig, sonst besteht eine gute Chance React wird das verwechseln Es ist auch wichtig, dass diese Schlüssel statisch bleiben bei allen Re-Renderings, um die beste Leistung zu erzielen.
Davon abgesehen muss man nicht immer das Obige anwenden, vorausgesetzt, es ist bekannt, dass das Array vollständig statisch ist. Die Anwendung von Best Practices wird jedoch nach Möglichkeit empfohlen.
Ein React Entwickler sagte in diesem GitHub-Problem :
- bei key geht es nicht wirklich um Leistung, sondern vielmehr um Identität (was wiederum zu einer besseren Leistung führt). zufällig zugewiesene und sich ändernde Werte sind keine Identität
- Wir können Schlüssel nicht [automatisch] realistisch bereitstellen, ohne zu wissen, wie Ihre Daten modelliert werden. Ich würde vorschlagen, vielleicht eine Art Hash-Funktion zu verwenden, wenn Sie keine IDs haben
- Wir haben bereits interne Schlüssel, wenn wir Arrays verwenden, aber sie sind der Index im Array. Wenn Sie ein neues Element einfügen, sind diese Schlüssel falsch.
Kurz gesagt, ein key
sollte sein:
key
Studieren Sie gemäß der obigen Erläuterung die folgenden Beispiele sorgfältig und versuchen Sie, den empfohlenen Ansatz nach Möglichkeit umzusetzen.
<tbody>
{rows.map((row, i) => {
return <ObjectRow key={i} />;
})}
</tbody>
Dies ist wohl der häufigste Fehler, der beim Durchlaufen eines Arrays in React auftritt. Dieser Ansatz ist technisch gesehen nicht "falsch", er ist nur ... "gefährlich", wenn Sie nicht wissen, was Sie tun. Wenn Sie durch ein statisches Array iterieren, ist dies eine absolut gültige Methode (z. B. eine Reihe von Links in Ihrem Navigationsmenü). Wenn Sie jedoch Elemente hinzufügen, entfernen, neu anordnen oder filtern, müssen Sie vorsichtig sein. Schauen Sie sich diese ausführliche Erklärung in der offiziellen Dokumentation an.
class MyApp extends React.Component {
constructor() {
super();
this.state = {
arr: ["Item 1"]
}
}
click = () => {
this.setState({
arr: ['Item ' + (this.state.arr.length+1)].concat(this.state.arr),
});
}
render() {
return(
<div>
<button onClick={this.click}>Add</button>
<ul>
{this.state.arr.map(
(item, i) => <Item key={i} text={"Item " + i}>{item + " "}</Item>
)}
</ul>
</div>
);
}
}
const Item = (props) => {
return (
<li>
<label>{props.children}</label>
<input value={props.text} />
</li>
);
}
ReactDOM.render(<MyApp />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
In diesem Snippet verwenden wir ein nicht statisches Array und beschränken uns nicht darauf, es als Stapel zu verwenden. Dies ist ein unsicherer Ansatz (Sie werden sehen, warum). Beachten Sie, wie beim Hinzufügen von Elementen am Anfang des Arrays (im Grunde genommen ohne Verschiebung) der Wert für jedes <input>
Beibehalten wird. Warum? Weil das key
nicht jedes Element eindeutig identifiziert.
Mit anderen Worten, zuerst hat Item 1
key={0}
. Wenn wir das zweite Element hinzufügen, wird das oberste Element zu Item 2
, Gefolgt von Item 1
Als zweitem Element. Jetzt hat Item 1
Jedoch key={1}
Und nicht mehr key={0}
. Stattdessen hat Item 2
Jetzt key={0}
!!
React denkt, die <input>
- Elemente haben sich nicht geändert, da das Item
mit der Taste 0
Immer oben steht!
Warum ist dieser Ansatz nur manchmal schlecht?
Dieser Ansatz ist nur dann riskant, wenn das Array irgendwie gefiltert, neu angeordnet oder Elemente hinzugefügt/entfernt werden. Wenn es immer statisch ist, ist es absolut sicher zu bedienen. Beispielsweise kann ein Navigationsmenü wie ["Home", "Products", "Contact us"]
Mit dieser Methode problemlos durchlaufen werden, da Sie wahrscheinlich niemals neue Links hinzufügen oder neu anordnen werden.
Kurz gesagt, hier ist, wann Sie sicher den Index als key
verwenden können:
Hätten wir stattdessen im obigen Snippet push das hinzugefügte Element am Ende des Arrays, wäre die Reihenfolge für jedes vorhandene Element immer korrekt.
<tbody>
{rows.map((row) => {
return <ObjectRow key={Math.random()} />;
})}
</tbody>
Während dieser Ansatz wahrscheinlich die Eindeutigkeit der Schlüssel garantiert, wird er always zwingen, jedes Element in der Liste erneut zu rendern, auch wenn dies nicht erforderlich ist. Dies ist eine sehr schlechte Lösung, da sie die Leistung stark beeinträchtigt. Ganz zu schweigen davon, dass man die Möglichkeit einer Schlüsselkollision nicht ausschließen kann, wenn Math.random()
zweimal dieselbe Zahl erzeugt.
Instabile Schlüssel (wie die von
Math.random()
erzeugten) führen dazu, dass viele Komponenteninstanzen und DOM-Knoten unnötigerweise neu erstellt werden, was zu Leistungseinbußen und zum Verlust des Status in untergeordneten Komponenten führen kann.
<tbody>
{rows.map((row) => {
return <ObjectRow key={row.uniqueId} />;
})}
</tbody>
Dies ist wahrscheinlich der beste Ansatz , da eine Eigenschaft verwendet wird, die für jedes Element im Dataset eindeutig ist. Wenn beispielsweise rows
Daten enthält, die aus einer Datenbank abgerufen wurden, kann der Primärschlüssel der Tabelle verwendet werden ( das ist normalerweise eine automatisch inkrementierende Zahl).
Die beste Möglichkeit, einen Schlüssel auszuwählen, besteht darin, eine Zeichenfolge zu verwenden, die ein Listenelement unter seinen Geschwistern eindeutig identifiziert. Am häufigsten würden Sie IDs aus Ihren Daten als Schlüssel verwenden
componentWillMount() {
let rows = this.props.rows.map(item => {
return {uid: SomeLibrary.generateUniqueID(), value: item};
});
}
...
<tbody>
{rows.map((row) => {
return <ObjectRow key={row.uid} />;
})}
</tbody>
Dies ist auch ein guter Ansatz. Wenn Ihr Datensatz keine Daten enthält, die die Eindeutigkeit garantieren ( z. B. ein Array von willkürlichen Zahlen), besteht die Möglichkeit einer Schlüsselkollision. In solchen Fällen ist es am besten, manuell eine eindeutige Kennung für jedes Element im Dataset zu generieren, bevor Sie darüber iterieren. Vorzugsweise beim Mounten der Komponente oder wenn der Datensatz empfangen wird ( zB von props
oder von einem asynchronen API-Aufruf), um dies nur zu tun einmal und nicht jedes Mal, wenn die Komponente neu gerendert wird. Es gibt bereits eine Handvoll Bibliotheken, die solche Schlüssel zur Verfügung stellen können. Hier ist ein Beispiel: React-Key-Index .
Warnung: Jedes untergeordnete Element in einem Array oder Iterator sollte eine eindeutige "Schlüssel" -Stütze haben.
Dies ist eine Warnung, da Array-Elemente, die wir durchlaufen, eine eindeutige Ähnlichkeit benötigen.
React behandelt das iterierende Komponenten-Rendering als Arrays.
Eine bessere Möglichkeit, dies zu beheben, ist die Bereitstellung eines Index für die Array-Elemente, die Sie durchlaufen. Beispiel:
class UsersState extends Component
{
state = {
users: [
{name:"shashank", age:20},
{name:"vardan", age:30},
{name:"somya", age:40}
]
}
render()
{
return(
<div>
{
this.state.users.map((user, index)=>{
return <UserState key={index} age={user.age}>{user.name}</UserState>
})
}
</div>
)
}
index ist React eingebaute Requisiten.
Fügen Sie einfach den eindeutigen Schlüssel zu Ihren Komponenten hinzu
data.map((marker)=>{
return(
<YourComponents
key={data.id} // <----- unique key
/>
);
})
Ich habe dies mit Hilfe von Guid für jeden Schlüssel wie folgt behoben:.
guid() {
return this.s4() + this.s4() + '-' + this.s4() + '-' + this.s4() + '-' +
this.s4() + '-' + this.s4() + this.s4() + this.s4();
}
s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
Und dann diesen Wert den Markierungen zuweisen:
{this.state.markers.map(marker => (
<MapView.Marker
key={this.guid()}
coordinate={marker.coordinates}
title={marker.title}
/>
))}
Check: key = undef !!!
Sie haben auch die Warnmeldung erhalten:
Each child in a list should have a unique "key" prop.
wenn Ihr Code richtig ist, aber wenn an
<ObjectRow key={someValue} />
someValue ist undefiniert !!! Bitte überprüfen Sie dies zuerst. Sie können Stunden sparen.
Die einfachste Lösung, die ich gefunden habe, ist das Erstellen einer eindeutigen ID für jedes Element in der Liste. Es gibt 2 Bibliotheken, uniqid und uuid.
npm install uniqid
Dann in Ihrem Code:
import uniqueid from 'uniqid'
- OR if you use require: var uniqid = require('uniqid');
Fügen Sie einfach einen Schlüssel zu dem HTML-Element hinzu, das es benötigt. Beachten Sie im folgenden Beispiel den key = {uniqueid ()}
{this.state.someList.map((item) => <li>{item}</li>)}
I changed to this:
{this.state.someList.map((item) => <li key={uniqueid()}>{item}</li>)}