Я не був задоволений жодним із запропонованих тут рішень. Насправді є дуже просте рішення, яке можна зробити за допомогою чистого Javascript, не покладаючись на якусь функціональність React, крім основного об'єкта реквізиту, - і це дає перевагу спілкування в будь-якому напрямку (батько -> дитина, дитина -> батько). Вам потрібно передати об’єкт від батьківського компонента до дочірнього компонента. Цей об'єкт - це те, що я називаю "двонаправленим посиланням" або коротко biRef. В основному, об'єкт містить посилання на методи у батьків, які батько хоче викрити. І дочірній компонент приєднує методи до об'єкта, який може викликати батько. Щось на зразок цього:
// Parent component.
function MyParentComponent(props) {
function someParentFunction() {
// The child component can call this function.
}
function onButtonClick() {
// Call the function inside the child component.
biRef.someChildFunction();
}
// Add all the functions here that the child can call.
var biRef = {
someParentFunction: someParentFunction
}
return <div>
<MyChildComponent biRef={biRef} />
<Button onClick={onButtonClick} />
</div>;
}
// Child component
function MyChildComponent(props) {
function someChildFunction() {
// The parent component can call this function.
}
function onButtonClick() {
// Call the parent function.
props.biRef.someParentFunction();
}
// Add all the child functions to props.biRef that you want the parent
// to be able to call.
props.biRef.someChildFunction = someChildFunction;
return <div>
<Button onClick={onButtonClick} />
</div>;
}
Інша перевага цього рішення полягає в тому, що ви можете додати набагато більше функцій у батька та дитини, передаючи їх від батька дитині, використовуючи лише одну властивість.
Поліпшенням коду, наведеним вище, є не додавання батьківських та дочірніх функцій безпосередньо до об'єкта biRef, а скоріше до членів. Батьківські функції повинні бути додані до члена, який називається "батьків", тоді як дочірні функції повинні бути додані до члена, який називається "дитина".
// Parent component.
function MyParentComponent(props) {
function someParentFunction() {
// The child component can call this function.
}
function onButtonClick() {
// Call the function inside the child component.
biRef.child.someChildFunction();
}
// Add all the functions here that the child can call.
var biRef = {
parent: {
someParentFunction: someParentFunction
}
}
return <div>
<MyChildComponent biRef={biRef} />
<Button onClick={onButtonClick} />
</div>;
}
// Child component
function MyChildComponent(props) {
function someChildFunction() {
// The parent component can call this function.
}
function onButtonClick() {
// Call the parent function.
props.biRef.parent.someParentFunction();
}
// Add all the child functions to props.biRef that you want the parent
// to be able to call.
props.biRef {
child: {
someChildFunction: someChildFunction
}
}
return <div>
<Button onClick={onButtonClick} />
</div>;
}
Розміщуючи функції батьків і дітей на окремих членах об'єкта biRef, ви матимете чисте розділення між ними та легко побачите, які з них належать батькові чи дитині. Це також допомагає запобігти випадковому перезапису батьківської функції дочірньому компоненту, якщо однакова функція відображається в обох.
Останнє - якщо ви зауважуєте, батьківський компонент створює об'єкт biRef з var, тоді як дочірній компонент отримує доступ до нього через об'єкт реквізиту. Це може бути заманливо не визначати об'єкт biRef у батьківському доступі та отримувати доступ до нього з його батьківського через власний параметр реквізиту (що може бути в ієрархії елементів інтерфейсу). Це ризиковано, оскільки дитина може подумати, що функція, яку він викликає, належить батькові до батьків, коли вона фактично може належати бабусі та дідусі. У цьому немає нічого поганого, якщо ви це усвідомлюєте. Якщо у вас немає причин підтримувати якусь ієрархію поза межами стосунків батько / дитина, краще створити biRef у своєму батьківському компоненті.