Как передать данные от дочернего компонента родительскому?

Передача данных от дочернего компонента к родительскому — одна из частых задач в React, несмотря на то, что поток данных в React по умолчанию односторонний (только сверху вниз). Однако React позволяет дочернему компоненту "сообщить" родителю какую-либо информацию через функции обратного вызова (callback-функции), которые передаются из родителя в дочернего через props. Это основной и рекомендуемый способ.

Суть метода

  1. Родительский компонент определяет функцию, которая будет обрабатывать или сохранять полученные данные.

  2. Он передаёт эту функцию дочернему компоненту через props.

  3. Дочерний компонент вызывает эту функцию с нужными данными, обычно в ответ на какое-либо событие (например, onClick, onChange).

Пример 1: Передача значения из <Child /> в <Parent />

function Parent() {
const handleDataFromChild = (data) => {
console.log('Получено от ребёнка:', data);
};
return &lt;Child onSendData={handleDataFromChild} /&gt;;
}
function Child({ onSendData }) {
const sendInfo = () => {
onSendData('Привет от дочернего компонента!');
};
return &lt;button onClick={sendInfo}&gt;Отправить данные родителю&lt;/button&gt;;
}

Что происходит:

  • Parent передаёт в Child функцию handleDataFromChild.

  • Внутри Child, при нажатии кнопки, вызывается onSendData и передаёт строку.

  • Родитель получает данные и может с ними что-то делать — сохранить в состояние, отобразить, отправить на сервер и т.п.

Пример 2: Использование данных формы в дочернем компоненте

function Parent() {
const \[name, setName\] = React.useState('');
const updateName = (value) => {
setName(value);
};
return (
&lt;div&gt;
&lt;Child onNameChange={updateName} /&gt;
&lt;p&gt;Имя: {name}&lt;/p&gt;
&lt;/div&gt;
);
}
function Child({ onNameChange }) {
const handleInput = (e) => {
onNameChange(e.target.value);
};
return &lt;input type="text" onChange={handleInput} placeholder="Введите имя" /&gt;;
}

Что происходит:

  • Parent определяет updateName, который обновляет name в состоянии.

  • Child вызывает onNameChange при каждом изменении текста.

  • Таким образом, родитель в реальном времени получает данные из поля ввода ребёнка.

Как можно дополнительно передавать данные

1. Объекты, массивы, числа, булевы значения

Можно передавать не только строки, но и любые типы данных:

onSendData({ name: 'Alice', age: 25 });

Родитель принимает и обрабатывает объект.

2. Функции высшего порядка

Можно передавать в ребёнка функцию, которая возвращает другую функцию:

&lt;Child send={(data) =&gt; processData(data)} />

Или использовать замыкания для более сложной логики.

3. useImperativeHandle + forwardRef (продвинутый случай)

Если дочерний компонент — это, например, модальное окно или сложный UI-элемент, родителю может потребоваться вызывать методы внутри него напрямую. Для этого используется forwardRef и useImperativeHandle.

const Child = React.forwardRef((props, ref) => {
React.useImperativeHandle(ref, () => ({
alertMessage() {
alert('Сообщение из дочернего компонента!');
},
}));
return &lt;div&gt;Я ребёнок&lt;/div&gt;;
});
function Parent() {
const childRef = React.useRef();
const handleClick = () => {
childRef.current.alertMessage();
};
return (
<>
&lt;Child ref={childRef} /&gt;
&lt;button onClick={handleClick}&gt;Вызвать метод ребёнка&lt;/button&gt;
&lt;/&gt;
);
}

Это позволяет родителю напрямую управлять дочерним компонентом, вызывая его методы. Такой подход полезен для нестандартных UI-решений, кастомных input-компонентов, модальных окон и т.п.

Зачем это может понадобиться

  • Обработка пользовательского ввода, например, формы.

  • Кнопка или действие в дочернем компоненте должно запустить загрузку, навигацию, отправку данных.

  • Дочерний компонент "отдаёт" результат выбора: выпадающий список, радиокнопки, слайдер.

  • Обратная связь с родителем, когда дочерний компонент завершил какую-то работу.

Потенциальные проблемы

  • Если передавать слишком много callback-функций, код может стать запутанным.

  • Может возникнуть "callback hell" при вложенности нескольких компонентов.

  • Каждый вызов callback-а вызывает перерендер родителя, если в нём изменяется состояние.

  • При передаче вглубь возникает проблема prop drilling, если промежуточные компоненты не используют эти функции, но вынуждены их передавать.

Альтернативы для сложных случаев

  • Context API: избавляет от необходимости прокидывать колбэки через уровни.

  • Redux, Zustand, Recoil и др.: позволяют всем компонентам обращаться к одному источнику данных.

  • EventEmitter (в библиотеках или кастомный): для событийной архитектуры в сложных проектах.

  • Custom hooks + shared state: можно выносить общую логику в хуки.

Практические советы

  • Функции, передаваемые в props, лучше мемоизировать с помощью useCallback, чтобы избежать лишних рендеров.

  • Следи за тем, чтобы имя функции отражало действие: onChange, onSubmit, onClose, onLogin.

  • В компоненте, получающем callback, вызывай его только при необходимости — не в render, а в обработчике событий или эффектах.