Комментарии (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>
);
}
Лучшие практики
- Передавай функции через props для простых случаев
- Используй useCallback для оптимизации
- Типизируй props функций в TypeScript
- Используй Context для часто передаваемых функций
- Избегай создания функций в пропсах (инлайн стрелочные функции перепроизводятся)
- Для событий используй имена вида onEventName (onDelete, onClick, onChange)