Düzenleme : ES6 güncelleştirilmiş örnekleri için son örneklere bakın.
Bu cevap, doğrudan ebeveyn-çocuk ilişkisi konusunu ele alır. Ebeveyn ve çocuk potansiyel olarak çok sayıda aracıya sahip olduğunda, bu yanıtı kontrol edin .
Diğer çözümlerin amacı eksik
Hala iyi çalışıyorken, diğer cevaplarda çok önemli bir şey eksik.
React.js'de bir çocuğun desteklerini olayları kullanarak ebeveynine iletmenin basit bir yolu yok mu?
Ebeveyn zaten bu çocuk pervane var! : Çocuğun bir pervane varsa, bunun nedeni ebeveyninin çocuğa pervane sağlamasıdır! Ebeveynin zaten bu pervane olduğu halde, çocuğun pervaneyi ebeveyne geri iletmesini neden istiyorsun?
Daha iyi uygulama
Çocuk : Gerçekten bundan daha karmaşık olması gerekmez.
var Child = React.createClass({
render: function () {
return <button onClick={this.props.onClick}>{this.props.text}</button>;
},
});
Bekar çocuklu ebeveyn : çocuğa geçtiği değeri kullanarak
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
Çocuk listesiyle birlikte ebeveyn : hala ebeveyn üzerinde ihtiyacınız olan her şeye sahipsiniz ve çocuğu daha karmaşık hale getirmenize gerek yok.
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
Kullanmak this.handleChildClick.bind(null,childIndex)
ve sonra kullanmak da mümkündürthis.state.childrenData[childIndex]
Bir null
bağlamla bağlandığımızı unutmayın, aksi halde React otomatik tarama sistemi ile ilgili bir uyarı yayınlar . Null kullanılması, işlev bağlamını değiştirmek istemediğiniz anlamına gelir. Ayrıca bakınız .
Diğer cevaplardaki kapsülleme ve kuplaj hakkında
Bu benim için eşleştirme ve kapsülleme açısından kötü bir fikir:
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} />
}
});
Destekleri kullanma : Yukarıda açıkladığım gibi, zaten ebeveynte desteklere sahipsiniz, bu nedenle desteklere erişmek için tüm alt öğeyi geçmek işe yaramaz.
Refs kullanma : Etkinlikte zaten tıklama hedefiniz var ve çoğu durumda bu yeterli. Ek olarak, doğrudan çocuk üzerinde bir ref kullanmış olabilirsiniz:
<Child ref="theChild" .../>
Ve üst öğedeki DOM düğümüne
React.findDOMNode(this.refs.theChild)
Ebeveynteki çocuğun birden fazla referansına erişmek istediğiniz daha gelişmiş durumlarda, çocuk tüm dom düğümlerini doğrudan geri çağrıda geçirebilir.
Bileşenin bir arayüzü (sahne) vardır ve ebeveyn, iç DOM yapısı veya hangi DOM düğümlerini başvurduğunu beyan ettiği de dahil olmak üzere çocuğun iç çalışması hakkında hiçbir şey varsaymamalıdır. Çocuğun ref'sini kullanan bir ebeveyn, 2 bileşeni sıkıca bağladığınız anlamına gelir.
Sorunu göstermek için, tarayıcıların içinde kaydırıcılar, kaydırma çubukları, video oynatıcılar gibi şeyler oluşturmak için kullanılan Shadow DOM ile ilgili bu alıntıyı alacağım ...:
Sizin, Web geliştiricisinin erişebildikleri ve uygulama ayrıntıları olarak kabul edilenler arasında bir sınır oluşturdular, böylece sizin için erişilemezler. Ancak tarayıcı, bu sınırın ötesinde tuzağa düşebilir. Bu sınır uygulandığında, tıpkı sizin yaptığınız gibi div ve yayılma alanlarından aynı eski Web teknolojilerini kullanarak tüm HTML öğelerini oluşturabildiler.
Sorun, çocuk uygulama ayrıntılarının ebeveyne sızmasına izin verirseniz, ebeveynleri etkilemeden çocuğu yeniden düzenlemeyi çok zorlaştırmanızdır. Bu, bir kütüphane yazarı (veya Shadow DOM'lu bir tarayıcı düzenleyicisi olarak) anlamına gelir, çünkü bu çok tehlikelidir, çünkü istemcinin çok fazla erişmesine izin verirsiniz ve geriye dönük uyumluluğu bozmadan kodu yükseltmeyi çok zorlaştırırsınız.
Chrome, kaydırma çubuğunu uyguladığında, istemcinin bu kaydırma çubuğunun iç dom düğümlerine erişmesine izin verdiyse, bu, istemcinin bu kaydırma çubuğunu kırma olasılığına sahip olabileceği ve Chrome'u, kaydırma çubuğu ... Bunun yerine, kaydırma çubuğunun bazı bölümlerini CSS ile özelleştirme gibi bazı güvenli şeylere erişim sağlarlar.
Başka bir şey kullanma hakkında
Tüm bileşeni geri aramada geçirmek tehlikelidir ve acemi geliştiricilerin ebeveynin içinde arama childComponent.setState(...)
veya childComponent.forceUpdate()
yeni değişkenler atama gibi çok garip şeyler yapmalarına yol açabilir ve tüm uygulamayı akla zorlaştırır.
Düzenle: ES6 örnekleri
Birçok kişi artık ES6 kullandığından, ES6 sözdizimi için aynı örnekler
Çocuk çok basit olabilir:
const Child = ({
onClick,
text
}) => (
<button onClick={onClick}>
{text}
</button>
)
Ebeveyn bir sınıf olabilir (ve sonunda devletin kendisini yönetebilir, ancak burada sahne olarak geçiyorum:
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>
);
}
}
Ancak, durumu yönetmesi gerekmiyorsa da basitleştirilebilir:
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 UYARISI (ES5 / ES6 için geçerlidir): PureComponent
veya shouldComponentUpdate
kullanıyorsanız onClick={e => doSomething()}
, üst oluşturma her oluşturulduğunda yeni bir işlev oluşturacağından, oluşturma işlemi sırasında doğrudan bağlama veya bağlama nedeniyle yukarıdaki uygulamalar varsayılan olarak optimize edilmez . Bu, uygulamanızda mükemmel bir darboğaz varsa, verileri çocuklara aktarabilir ve optimizasyonun başlayabilmesi için "kararlı" geri arama (üst sınıfta ayarlanır ve this
sınıf yapıcısına bağlanır ) içinde yeniden enjekte PureComponent
edebilirsiniz. kendiniz uygulayabilir shouldComponentUpdate
ve sahne karşılaştırma karşılaştırmasında geri aramayı yoksayabilirsiniz.
İnce ayarlı optimizasyonlar elde etmek için daha yüksek dereceli bileşenler sağlayan Yeniden Oluşturma kitaplığını da kullanabilirsiniz :
// 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)
Bu durumda, Child bileşenini aşağıdakileri kullanarak optimize edebilirsiniz:
const OptimizedChild = onlyUpdateForKeys(['text'])(Child)