Я не был удовлетворен ни одним из решений, представленных здесь. На самом деле существует очень простое решение, которое может быть сделано с использованием чистого Javascript, не полагаясь на некоторые функциональные возможности React, кроме базового объекта props, и дает вам преимущество общения в любом направлении (parent -> child, child -> parent). Вам необходимо передать объект из родительского компонента в дочерний компонент. Этот объект - это то, что я называю «двунаправленной ссылкой» или для краткости 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», тогда как дочерние функции должны быть добавлены к члену с именем «child».
// 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, тогда как дочерний компонент обращается к нему через объект props. Может быть соблазнительно не определять объект biRef в родительском объекте и обращаться к нему от его родительского объекта через собственный параметр props (что может иметь место в иерархии элементов пользовательского интерфейса). Это рискованно, потому что ребенок может подумать, что функция, которую он вызывает у родителя, принадлежит родителю, когда он на самом деле может принадлежать дедушке. В этом нет ничего плохого, если вы знаете об этом. Если у вас нет причин для поддержки какой-либо иерархии, выходящей за рамки родительских и дочерних отношений, лучше всего создать biRef в родительском компоненте.