Skip to main content
Практика завдань

Синтетичні події в React

Що таке Синтетичні Події?

Синтетичні Події — це обгортка React навколо рідних подій браузера. React створює єдину систему подій, яка працює однаково в усіх браузерах.

javascript
function Button() { function handleClick(event) { console.log(event); // SyntheticEvent, а не native Event } return <button onClick={handleClick}>Натисни на мене</button>; }

Чому вони потрібні?

Кросбраузерна сумісність

Різні браузери мають різні реалізації подій. Синтетичні Події уніфікують API:

javascript
function Input() { function handleChange(event) { // event.target.value працює однаково скрізь console.log(event.target.value); } return <input onChange={handleChange} />; }

Продуктивність

React використовує делегування подій: всі обробники прикріплюються до кореневого елемента, а не до кожного елемента окремо.

javascript
// Замість 1000 обробників на кожній кнопці // React створює один обробник на корені function List({ items }) { return ( <ul> {items.map(item => ( <li key={item.id}> <button onClick={() => console.log(item.id)}> {item.name} </button> </li> ))} </ul> ); }

API Синтетичних Подій

Синтетична Подія має той же інтерфейс, що й рідні події:

javascript
function Form() { function handleSubmit(event) { event.preventDefault(); // Працює як рідна подія event.stopPropagation(); console.log(event.type); // 'submit' console.log(event.target); // посилання на елемент console.log(event.currentTarget); // елемент з обробником } return ( <form onSubmit={handleSubmit}> <button type="submit">Відправити</button> </form> ); }

Пулінг Подій (до React 17)

У React 16 і раніше події повторно використовувалися для підвищення продуктивності:

javascript
// React 16 і раніше function handleClick(event) { console.log(event.type); // 'click' setTimeout(() => { console.log(event.type); // null, подія очищена! }, 0); }

Щоб зберегти подію, ви використовували event.persist():

javascript
function handleClick(event) { event.persist(); // Зберегти подію setTimeout(() => { console.log(event.type); // 'click', працює! }, 0); }

React 17+:

У React 17 пулінг подій був видалений. Події більше не очищуються, event.persist() не потрібен.


Доступ до рідної події

Ви можете отримати рідну подію через nativeEvent:

javascript
function handleClick(event) { console.log(event); // SyntheticEvent console.log(event.nativeEvent); // Рідна подія браузера // Корисно для специфічних функцій браузера console.log(event.nativeEvent.path); }

Відмінності від рідних подій

Іменування

React використовує camelCase замість малих літер:

javascript
// HTML <button onclick="handleClick()">Натисни</button> // React <button onClick={handleClick}>Натисни</button>

Повернення false

В HTML ви можете повернути false, щоб запобігти стандартній дії:

html
<!-- HTML --> <a href="#" onclick="console.log('натиснуто'); return false"> Посилання </a>

В React ви повинні явно викликати preventDefault():

javascript
// React function Link() { function handleClick(event) { event.preventDefault(); console.log('натиснуто'); } return <a href="#" onClick={handleClick}>Посилання</a>; }

Підтримувані події

React підтримує всі стандартні DOM події:

Мишині події

javascript
onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp

Клавіатурні події

javascript
function Input() { function handleKeyDown(event) { if (event.key === 'Enter') { console.log('Натиснуто Enter'); } } return <input onKeyDown={handleKeyDown} />; }

Події форм

javascript
function Form() { return ( <form onSubmit={e => e.preventDefault()} onChange={e => console.log('змінено')} onFocus={e => console.log('в фокусі')} onBlur={e => console.log('втрата фокусу')} > <input type="text" /> </form> ); }

Події фокусу

javascript
onFocus onBlur

Сенсорні події

javascript
onTouchStart onTouchMove onTouchEnd onTouchCancel

Делегування подій

React 16 і раніше

Події прикріплювалися до document:

javascript
// React прикріплював обробники до document document.addEventListener('click', handleAllClicks);

React 17+

Події прикріплюються до кореневого вузла React:

javascript
// React прикріплює до кореня додатку const root = document.getElementById('root'); root.addEventListener('click', handleAllClicks);

Це важливо при використанні кількох версій React на одній сторінці або інтеграції з іншими бібліотеками.


Специфіка обробки подій

onChange проти onInput

В React onChange працює як рідний onInput — спрацьовує на кожну зміну:

javascript
function Input() { const [value, setValue] = useState(''); return ( <input value={value} // Спрацьовує на кожен натиск клавіші onChange={e => setValue(e.target.value)} /> ); }

onScroll

onScroll не спрацьовує в React (як в DOM), але React надає його для зручності:

javascript
function ScrollableDiv() { function handleScroll(event) { console.log(event.target.scrollTop); } return ( <div onScroll={handleScroll} style={{ height: 200, overflow: 'auto' }}> {/* Багато контенту */} </div> ); }

Пряме прикріплення рідного обробника

Іноді вам потрібно прикріпити рідний обробник безпосередньо:

javascript
function Component() { const ref = useRef(null); useEffect(() => { const element = ref.current; function handleNativeClick(event) { console.log('Рідний клік', event); } element.addEventListener('click', handleNativeClick); return () => { element.removeEventListener('click', handleNativeClick); }; }, []); return <div ref={ref}>Натисни на мене</div>; }

Попередження:

Будьте обережні з прямими обробниками — не забудьте видалити їх у функції очищення.


Захоплення подій

React підтримує фазу захоплення:

javascript
function Parent() { return ( <div onClickCapture={() => console.log('1. Захоплення батька')} onClick={() => console.log('3. Бульбашка батька')} > <button onClickCapture={() => console.log('2. Захоплення кнопки')} onClick={() => console.log('4. Бульбашка кнопки')} > Натисни </button> </div> ); } // Натискання кнопки виведе: // 1. Захоплення батька // 2. Захоплення кнопки // 4. Бульбашка кнопки // 3. Бульбашка батька

Типізація TypeScript

typescript
import { MouseEvent, ChangeEvent, FormEvent } from 'react'; function Component() { function handleClick(event: MouseEvent<HTMLButtonElement>) { console.log(event.currentTarget.name); } function handleChange(event: ChangeEvent<HTMLInputElement>) { console.log(event.target.value); } function handleSubmit(event: FormEvent<HTMLFormElement>) { event.preventDefault(); } return ( <form onSubmit={handleSubmit}> <input onChange={handleChange} /> <button onClick={handleClick}>Відправити</button> </form> ); }

Загальні помилки

Асинхронне використання подій (React 16)

javascript
// Неправильно в React 16 function handleClick(event) { setTimeout(() => { console.log(event.type); // null! }, 0); } // Правильно function handleClick(event) { const eventType = event.type; // Зберегти значення setTimeout(() => { console.log(eventType); // 'click' }, 0); }

Передача події до setState

javascript
// Неправильно function handleChange(event) { setState(prevState => ({ ...prevState, value: event.target.value // подія може бути очищена })); } // Правильно function handleChange(event) { const newValue = event.target.value; setState(prevState => ({ ...prevState, value: newValue })); }

Висновок

Синтетичні Події:

  • Обгортка навколо рідних подій браузера
  • Забезпечують кросбраузерну сумісність
  • Використовують делегування для продуктивності
  • Мають той же API, що й рідні події
  • У React 17+ не очищуються автоматично
  • Використовують camelCase для іменування
  • Рідна подія доступна через nativeEvent

На співбесідах:

Важливо вміти:

  • Пояснити, що таке Синтетичні Події і чому вони потрібні
  • Описати делегування подій
  • Пояснити відмінності від рідних подій
  • Описати зміни в React 17 (пулінг подій)
  • Показати, як отримати доступ до рідної події

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань