Передача функций как props

Передача функций через props — ключевой паттерн в React для обеспечения взаимодействия между компонентами при сохранении одностороннего потока данных. Поскольку дочерние компоненты не могут напрямую изменять состояние родителя, они вызывают переданные функции-колбэки, чтобы запросить изменение.

Как передать функцию в дочерний компонент

Родительский компонент определяет функцию (обычно с использованием useState или других хуков) и передаёт её как prop:

function Parent() {
  const [isVisible, setIsVisible] = useState(false);

  return (
    <TogglePanel onToggle={() => setIsVisible(!isVisible)} />
  );
}

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

function TogglePanel({ onToggle }) {
  return <button onClick={onToggle}>Переключить</button>;
}

Почему это важно

Такой подход сохраняет единственный источник истины: состояние остаётся в том компоненте, которому оно принадлежит. Дочерний компонент лишь сигнализирует о намерении изменить данные, не зная и не контролируя их внутреннюю структуру. Это делает компоненты более переиспользуемыми и тестируемыми.

Передача параметров в колбэк

Функции-props могут принимать аргументы, что особенно полезно в списках или формах:

function TodoList({ todos, onDelete }) {
  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>
          {todo.text}
          <button onClick={() => onDelete(todo.id)}>Удалить</button>
        </li>
      ))}
    </ul>
  );
}

// В родителе
<TodoList todos={todos} onDelete={(id) => setTodos(todos.filter(t => t.id !== id))} />

Здесь стрелочная функция () => onDelete(todo.id) оборачивает вызов, чтобы передать конкретный id.

Оптимизация: избегание лишних пересозданий

При каждом рендере родителя передаваемая функция создаётся заново, что может вызывать ненужные ререндеры дочерних компонентов. Для оптимизации используют useCallback:

const handleToggle = useCallback(() => setIsVisible(v => !v), []);
return <TogglePanel onToggle={handleToggle} />;

Это особенно актуально при использовании React.memo или в производительных сценариях.