Bearbeiten : In den Endbeispielen finden Sie aktualisierte ES6-Beispiele.
Diese Antwort behandelt einfach den Fall einer direkten Eltern-Kind-Beziehung. Wenn Eltern und Kind möglicherweise viele Vermittler haben, überprüfen Sie diese Antwort .
Andere Lösungen verfehlen den Punkt
Während sie noch gut funktionieren, fehlt anderen Antworten etwas sehr Wichtiges.
Gibt es nicht eine einfache Möglichkeit, die Requisiten eines Kindes mithilfe von Ereignissen in React.js an die Eltern weiterzugeben?
Der Elternteil hat bereits diese Kinderstütze! : Wenn das Kind eine Requisite hat, dann deshalb, weil sein Elternteil dem Kind diese Requisite zur Verfügung gestellt hat! Warum soll das Kind die Requisite an die Eltern zurückgeben, während die Eltern diese Requisite offensichtlich bereits haben?
Bessere Umsetzung
Kind : Es muss wirklich nicht komplizierter sein.
var Child = React.createClass({
render: function () {
return <button onClick={this.props.onClick}>{this.props.text}</button>;
},
});
Eltern mit einem einzelnen Kind : Verwenden des Werts, der an das Kind übergeben wird
var Parent = React.createClass({
getInitialState: function() {
return {childText: "Click me! (parent prop)"};
},
render: function () {
return (
<Child onClick={this.handleChildClick} text={this.state.childText}/>
);
},
handleChildClick: function(event) {
// You can access the prop you pass to the children
// because you already have it!
// Here you have it in state but it could also be
// in props, coming from another parent.
alert("The Child button text is: " + this.state.childText);
// You can also access the target of the click here
// if you want to do some magic stuff
alert("The Child HTML is: " + event.target.outerHTML);
}
});
JsFiddle
Elternteil mit Liste der Kinder : Sie haben immer noch alles, was Sie brauchen, auf dem Elternteil und müssen das Kind nicht komplizierter machen.
var Parent = React.createClass({
getInitialState: function() {
return {childrenData: [
{childText: "Click me 1!", childNumber: 1},
{childText: "Click me 2!", childNumber: 2}
]};
},
render: function () {
var children = this.state.childrenData.map(function(childData,childIndex) {
return <Child onClick={this.handleChildClick.bind(null,childData)} text={childData.childText}/>;
}.bind(this));
return <div>{children}</div>;
},
handleChildClick: function(childData,event) {
alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
alert("The Child HTML is: " + event.target.outerHTML);
}
});
JsFiddle
Es ist auch möglich, zu verwenden this.handleChildClick.bind(null,childIndex)und dann zu verwendenthis.state.childrenData[childIndex]
Beachten Sie, dass wir mit einem nullKontext binden, da React andernfalls eine Warnung bezüglich seines Autobindungssystems ausgibt . Die Verwendung von null bedeutet, dass Sie den Funktionskontext nicht ändern möchten. Siehe auch .
Über Kapselung und Kopplung in anderen Antworten
Dies ist für mich eine schlechte Idee in Bezug auf Kopplung und Einkapselung:
var Parent = React.createClass({
handleClick: function(childComponent) {
// using childComponent.props
// using childComponent.refs.button
// or anything else using childComponent
},
render: function() {
<Child onClick={this.handleClick} />
}
});
Verwenden von Requisiten : Wie oben erläutert, haben Sie die Requisiten bereits im übergeordneten Element, sodass es sinnlos ist, die gesamte untergeordnete Komponente für den Zugriff auf Requisiten zu übergeben.
Verwenden von Refs : Sie haben bereits das Klickziel im Ereignis, und in den meisten Fällen reicht dies aus. Außerdem hätten Sie einen Ref direkt für das Kind verwenden können:
<Child ref="theChild" .../>
Und greifen Sie mit auf den DOM-Knoten im übergeordneten Knoten zu
React.findDOMNode(this.refs.theChild)
In fortgeschritteneren Fällen, in denen Sie auf mehrere Refs des untergeordneten Elements im übergeordneten Element zugreifen möchten, kann das untergeordnete Element alle dom-Knoten direkt im Rückruf übergeben.
Die Komponente verfügt über eine Schnittstelle (Requisiten), und der Elternteil sollte nichts über die innere Arbeitsweise des Kindes annehmen, einschließlich seiner inneren DOM-Struktur oder der DOM-Knoten, für die er Refs deklariert. Ein Elternteil, der eine Referenz eines Kindes verwendet, bedeutet, dass Sie die beiden Komponenten eng miteinander verbinden.
Um das Problem zu veranschaulichen, nehme ich dieses Zitat über das Shadow DOM , das in Browsern verwendet wird, um Dinge wie Schieberegler, Bildlaufleisten, Videoplayer zu rendern ...:
Sie haben eine Grenze zwischen dem, was Sie als Webentwickler erreichen können, und den Implementierungsdetails geschaffen, auf die Sie keinen Zugriff haben. Der Browser kann diese Grenze jedoch nach Belieben überschreiten. Mit dieser Grenze konnten sie alle HTML-Elemente mit denselben guten alten Webtechnologien aus den Divs und Spans erstellen, genau wie Sie es tun würden.
Das Problem besteht darin, dass es sehr schwierig ist, das untergeordnete Element zu überarbeiten, ohne dass sich dies auf das übergeordnete Element auswirkt, wenn Sie die untergeordneten Implementierungsdetails in das übergeordnete Element übertragen. Dies bedeutet, dass dies als Bibliotheksautor (oder als Browser-Editor mit Shadow DOM) sehr gefährlich ist, da Sie dem Client zu viel Zugriff gewähren, was es sehr schwierig macht, Code zu aktualisieren, ohne die Retrokompatibilität zu beeinträchtigen.
Wenn Chrome seine Bildlaufleiste implementiert hat, mit der der Client auf die inneren Domänenknoten dieser Bildlaufleiste zugreifen kann, bedeutet dies, dass der Client möglicherweise die Möglichkeit hat, diese Bildlaufleiste einfach zu beschädigen, und dass Apps leichter beschädigt werden, wenn Chrome nach dem Refactoring die automatische Aktualisierung durchführt Bildlaufleiste ... Stattdessen bieten sie nur Zugriff auf einige sichere Dinge wie das Anpassen einiger Teile der Bildlaufleiste mit CSS.
Über die Verwendung von etwas anderem
Die gesamte Komponente in der Callback - Passing ist gefährlich und Anfänger Entwickler führen können sehr seltsame Dinge zu tun , wie der Aufruf childComponent.setState(...)oder childComponent.forceUpdate(), oder es neue Variablen, innerhalb des übergeordneten, so dass die ganze app viel schwieriger zu Grund , sich über die Zuordnung.
Bearbeiten: ES6-Beispiele
Da viele Leute jetzt ES6 verwenden, finden Sie hier dieselben Beispiele für die ES6-Syntax
Das Kind kann sehr einfach sein:
const Child = ({
onClick,
text
}) => (
<button onClick={onClick}>
{text}
</button>
)
Das Elternteil kann entweder eine Klasse sein (und es kann schließlich den Staat selbst verwalten, aber ich gebe es hier als Requisiten weiter:
class Parent1 extends React.Component {
handleChildClick(childData,event) {
alert("The Child button data is: " + childData.childText + " - " + childData.childNumber);
alert("The Child HTML is: " + event.target.outerHTML);
}
render() {
return (
<div>
{this.props.childrenData.map(child => (
<Child
key={child.childNumber}
text={child.childText}
onClick={e => this.handleChildClick(child,e)}
/>
))}
</div>
);
}
}
Es kann aber auch vereinfacht werden, wenn der Status nicht verwaltet werden muss:
const Parent2 = ({childrenData}) => (
<div>
{childrenData.map(child => (
<Child
key={child.childNumber}
text={child.childText}
onClick={e => {
alert("The Child button data is: " + child.childText + " - " + child.childNumber);
alert("The Child HTML is: " + e.target.outerHTML);
}}
/>
))}
</div>
)
JsFiddle
PERF-WARNUNG (gilt für ES5 / ES6): Wenn Sie PureComponentoder verwenden shouldComponentUpdate, werden die oben genannten Implementierungen nicht standardmäßig optimiert onClick={e => doSomething()}, da sie während der Renderphase verwendet oder direkt gebunden werden, da bei jedem Rendern des übergeordneten Elements eine neue Funktion erstellt wird. Wenn dies ein perfekter Engpass in Ihrer App ist, können Sie die Daten an die untergeordneten Elemente übergeben und sie innerhalb des "stabilen" Rückrufs (der für die übergeordnete Klasse festgelegt und an den Klassenkonstruktor gebunden ist this) erneut einfügen, damit die PureComponentOptimierung aktiviert werden kann, oder Sie Sie können Ihre eigenen implementieren shouldComponentUpdateund den Rückruf in der Requisitenvergleichsprüfung ignorieren.
Sie können auch die Recompose- Bibliothek verwenden, die Komponenten höherer Ordnung bereitstellt, um fein abgestimmte Optimierungen zu erzielen:
// A component that is expensive to render
const ExpensiveComponent = ({ propA, propB }) => {...}
// Optimized version of same component, using shallow comparison of props
// Same effect as React's PureRenderMixin
const OptimizedComponent = pure(ExpensiveComponent)
// Even more optimized: only updates if specific prop keys have changed
const HyperOptimizedComponent = onlyUpdateForKeys(['propA', 'propB'])(ExpensiveComponent)
In diesem Fall können Sie die untergeordnete Komponente optimieren, indem Sie Folgendes verwenden:
const OptimizedChild = onlyUpdateForKeys(['text'])(Child)