5 эффективных способов передачи данных от дочернего компонента к родительскому с помощью React Hooks

В React передача данных из дочернего компонента в родительский является общим требованием. С появлением React Hooks управление состоянием и связью между компонентами стало еще более эффективным. В этом сообщении блога мы рассмотрим пять эффективных методов выполнения этой задачи с помощью React Hooks. Мы углубимся в примеры кода и будем использовать разговорный язык, чтобы сделать концепции легко понятными. Давайте начнем!

  1. Функции обратного вызова.
    Один из самых простых способов отправить данные из дочернего компонента в его родительский — использовать функции обратного вызова. Вот пример:

Родительский компонент:

import React, { useState } from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
  const [data, setData] = useState('');
  const handleDataChange = (newData) => {
    setData(newData);
  };
  return (
    <div>
      <h2>Parent Component</h2>
      <ChildComponent onDataChange={handleDataChange} />
      <p>Received data: {data}</p>
    </div>
  );
};
export default ParentComponent;

Дочерний компонент:

import React from 'react';
const ChildComponent = ({ onDataChange }) => {
  const sendDataToParent = () => {
    const newData = 'Hello from child!';
    onDataChange(newData);
  };
  return (
    <div>
      <h3>Child Component</h3>
      <button onClick={sendDataToParent}>Send Data</button>
    </div>
  );
};
export default ChildComponent;

В этом примере дочерний компонент ChildComponentполучает функцию обратного вызова onDataChangeв качестве реквизита от своего родительского компонента ParentComponent. Когда кнопка нажимается в дочернем компоненте, она вызывает функцию sendDataToParent, которая вызывает обратный вызов onDataChangeс новыми данными.

  1. Context API.
    Еще один мощный метод передачи данных от дочернего компонента к родительскому — использование Context API. Вот пример:
import React, { createContext, useContext, useState } from 'react';
const DataContext = createContext();
const ParentComponent = () => {
  const [data, setData] = useState('');
  const handleDataChange = (newData) => {
    setData(newData);
  };
  return (
    <div>
      <h2>Parent Component</h2>
      <DataContext.Provider value={handleDataChange}>
        <ChildComponent />
      </DataContext.Provider>
      <p>Received data: {data}</p>
    </div>
  );
};
const ChildComponent = () => {
  const onDataChange = useContext(DataContext);
  const sendDataToParent = () => {
    const newData = 'Hello from child!';
    onDataChange(newData);
  };
  return (
    <div>
      <h3>Child Component</h3>
      <button onClick={sendDataToParent}>Send Data</button>
    </div>
  );
};
export default ParentComponent;

В этом примере мы создаем DataContextс помощью функции createContextи предоставляем функцию handleDataChangeв качестве значения. Дочерний компонент ChildComponentиспользует хук useContextдля доступа к функции onDataChangeиз контекста. При нажатии кнопки вызывается функция sendDataToParent, передающая новые данные родительскому компоненту.

  1. Пользовательские перехватчики.
    Пользовательские перехватчики позволяют нам инкапсулировать логику и распределять ее между компонентами. Мы можем создать собственный крючок для передачи данных от дочернего компонента к родительскому. Вот пример:
import React, { useState } from 'react';
const useDataPassing = () => {
  const [data, setData] = useState('');
  const handleDataChange = (newData) => {
    setData(newData);
  };
  return [data, handleDataChange];
};
const ParentComponent = () => {
  const [data, handleDataChange] = useDataPassing();
  return (
    <div>
      <h2>Parent Component</h2>
      <ChildComponent onDataChange={handleDataChange} />
      <p>Received data: {data}</p>
    </div>
  );
};
const ChildComponent = ({ onDataChange }) => {
  const sendDataToParent = () => {
    const newData = 'Hello from child!';
    onDataChange(newData);
  };
  return (
    <div>
      <h3>Child Component</h3>
      <button onClick={sendDataToParent}>Send Data</button>
    </div>
  );
};
export default ParentComponent;

В этом примере мы определяем специальный хук useDataPassing, который возвращает состояние dataи функцию handleDataChange. Родительский компонент ParentComponentиспользует пользовательский хук для получения функций dataи handleDataChange. Дочерний компонент ChildComponentполучает функцию handleDataChangeв качестве реквизита и вызывает ее с новыми данными при нажатии кнопки.

  1. EventEmitter:
    Если вы предпочитаете подход, основанный на событиях, вы можете использовать генератор событий для передачи данных от дочернего компонента к родительскому. Вот пример использования библиотеки eventemitter3:
import React, { useEffect } from 'react';
import { EventEmitter } from 'eventemitter3';
const emitter = new EventEmitter();
const ParentComponent = () => {
  useEffect(() => {
    const handleDataChange = (newData) => {
      console.log('Received data:', newData);
    };
    emitter.on('dataChange', handleDataChange);
    return () => {
      emitter.off('dataChange', handleDataChange);
    };
  }, []);
  return (
    <div>
      <h2>Parent Component</h2>
      <ChildComponent />
    </div>
  );
};
const ChildComponent = () => {
  const sendDataToParent = () => {
    const newData = 'Hello from child!';
    emitter.emit('dataChange', newData);
  };
  return (
    <div>
      <h3>Child Component</h3>
      <button onClick={sendDataToParent}>Send Data</button>
    </div>
  );
};
export default ParentComponent;

В этом примере мы создаем экземпляр класса EventEmitter, предоставленный библиотекой eventemitter3. Родительский компонент ParentComponentпрослушивает событие 'dataChange'и обрабатывает его, регистрируя полученные данные. Дочерний компонент ChildComponentгенерирует событие 'dataChange'с новыми данными при нажатии кнопки.

  1. Redux или React Context с редукторами:
    Если вы уже используете Redux или React Context с редукторами в своем приложении, вы можете использовать их для передачи данных от дочерних компонентов к родительским. Диспетчеризируя действия или обновляя состояние через редукторы, вы можете добиться такого взаимодействия. Вот пример использования Redux:
// Redux setup and configuration
// Parent component
const ParentComponent = () => {
  const data = useSelector((state) => state.data);
  return (
    <div>
      <h2>Parent Component</h2>
      <ChildComponent />
      <p>Received data: {data}</p>
    </div>
  );
};
// Child component
const ChildComponent = () => {
  const dispatch = useDispatch();
  const sendDataToParent = () => {
    const newData = 'Hello from child!';
    dispatch({ type: 'UPDATE_DATA', payload: newData });
  };
  return (
    <div>
      <h3>Child Component</h3>
      <button onClick={sendDataToParent}>Send Data</button>
    </div>
  );
};
export default ParentComponent;

В этом примере родительский компонент ParentComponentиспользует хук useSelectorдля доступа к dataиз хранилища Redux. Дочерний компонент ChildComponentиспользует хук useDispatchдля отправки действия с новыми данными для обновления хранилища Redux.

В этом сообщении блога мы рассмотрели пять эффективных методов передачи данных от дочерних компонентов к родительским с помощью React Hooks. Мы рассмотрели функции обратного вызова, Context API, пользовательские перехватчики, генераторы событий и контекст Redux/React с редукторами. Эти методы предоставляют различные варианты в зависимости от требований и предпочтений вашего проекта. Реализуя эти методы, вы можете улучшить взаимодействие и поток данных между вашими компонентами React. Приятного кодирования!