← Назад к вопросам

Как передается функция в дочерний компонент?

1.2 Junior🔥 101 комментариев
#React

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Передача функций в дочерние компоненты (React)

Передача функций между компонентами - основной механизм для обмена данными и событиями в React. Это называется "поднятием состояния" (lifting state up).

Базовая передача функции как props

Дочерний компонент получает функцию как свойство и может её вызвать:

// Дочерний компонент
function Button({ onClick, children }) {
  return (
    <button onClick={onClick}>
      {children}
    </button>
  );
}

// Родительский компонент
function Parent() {
  const handleClick = () => {
    console.log('Кнопка нажата!');
  };

  return (
    <Button onClick={handleClick}>
      Нажми меня
    </Button>
  );
}

Передача параметров через функцию

Дочерний компонент может передавать данные обратно родителю через параметры функции:

// Дочерний компонент
function TodoItem({ onDelete, id, text }) {
  return (
    <div>
      <span>{text}</span>
      <button onClick={() => onDelete(id)}>
        Удалить
      </button>
    </div>
  );
}

// Родительский компонент
function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: 'Купить молоко' },
    { id: 2, text: 'Сделать домашку' }
  ]);

  const handleDelete = (id) => {
    setTodos(todos.filter(todo => todo.id !== id));
  };

  return (
    <div>
      {todos.map(todo => (
        <TodoItem
          key={todo.id}
          id={todo.id}
          text={todo.text}
          onDelete={handleDelete}
        />
      ))}
    </div>
  );
}

useCallback для оптимизации

Используй useCallback, чтобы избежать ненужных пересчётов функции:

function Parent() {
  const [count, setCount] = useState(0);

  // Без useCallback функция создаётся заново при каждом рендере
  // const handleClick = () => console.log(count);

  // С useCallback функция переиспользуется, пока зависимости не изменились
  const handleClick = useCallback(() => {
    console.log('Count:', count);
  }, [count]);  // Функция пересоздаётся только если count изменится

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ExpensiveChild onClick={handleClick} />
    </div>
  );
}

function ExpensiveChild({ onClick }) {
  console.log('Дочерний компонент отрендерился');
  return <button onClick={onClick}>Click me</button>;
}

Передача методов класса

В классовых компонентах нужно привязывать this:

class Parent extends React.Component {
  constructor(props) {
    super(props);
    // Вариант 1: Привязать в конструкторе
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    console.log('Clicked');
  }

  render() {
    return (
      <div>
        {/* Вариант 1: Функция уже привязана */}
        <Child onClick={this.handleClick} />

        {/* Вариант 2: Привязать через стрелочную функцию */}
        <Child onClick={() => this.handleClick()} />

        {/* Вариант 3: Объявить как поле класса */}
        <Child onClick={this.handleClickArrow} />
      </div>
    );
  }

  // Стрелочная функция автоматически привязана
  handleClickArrow = () => {
    console.log('Clicked');
  };
}

Типизация в TypeScript

interface ButtonProps {
  onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
  children: React.ReactNode;
}

function Button({ onClick, children }: ButtonProps) {
  return <button onClick={onClick}>{children}</button>;
}

interface TodoItemProps {
  id: number;
  text: string;
  onDelete: (id: number) => void;  // Функция, принимающая id
  onToggle?: (id: number, done: boolean) => void;  // Опциональная функция
}

function TodoItem({ id, text, onDelete, onToggle }: TodoItemProps) {
  return (
    <div>
      <input
        type="checkbox"
        onChange={(e) => onToggle?.(id, e.target.checked)}
      />
      <span>{text}</span>
      <button onClick={() => onDelete(id)}>Удалить</button>
    </div>
  );
}

Передача нескольких функций

function Form() {
  const handleSubmit = (data) => {
    console.log('Form submitted:', data);
  };

  const handleCancel = () => {
    console.log('Form cancelled');
  };

  const handleChange = (fieldName, value) => {
    console.log(`${fieldName}: ${value}`);
  };

  return (
    <FormComponent
      onSubmit={handleSubmit}
      onCancel={handleCancel}
      onChange={handleChange}
    />
  );
}

function FormComponent({ onSubmit, onCancel, onChange }) {
  const [formData, setFormData] = useState({ name: '', email: '' });

  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
    onChange(name, value);  // Передать изменение родителю
  };

  return (
    <form>
      <input
        name="name"
        value={formData.name}
        onChange={handleInputChange}
      />
      <input
        name="email"
        value={formData.email}
        onChange={handleInputChange}
      />
      <button onClick={() => onSubmit(formData)}>Submit</button>
      <button type="button" onClick={onCancel}>Cancel</button>
    </form>
  );
}

Контекст для передачи функций глубоко

Когда нужно передать функцию через много уровней, используй Context:

const ThemeContext = React.createContext();

function App() {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme(prev => prev === 'light' ? 'dark' : 'light');
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      <Layout />
    </ThemeContext.Provider>
  );
}

// Компонент глубоко вложенный
function DeepChild() {
  const { theme, toggleTheme } = useContext(ThemeContext);
  return (
    <button onClick={toggleTheme}>
      Current theme: {theme}
    </button>
  );
}

Лучшие практики

  1. Передавай функции через props для простых случаев
  2. Используй useCallback для оптимизации
  3. Типизируй props функций в TypeScript
  4. Используй Context для часто передаваемых функций
  5. Избегай создания функций в пропсах (инлайн стрелочные функции перепроизводятся)
  6. Для событий используй имена вида onEventName (onDelete, onClick, onChange)