Урок 03

Типизация событий

React оборачивает нативные события в SyntheticEvent. Для каждого типа события есть свой тип.

onClick

import type { MouseEvent } from 'react';

function Button() {
    function handleClick(e: MouseEvent<HTMLButtonElement>) {
        console.log(e.clientX, e.clientY);
    }

    return <button onClick={handleClick}>OK</button>;
}

MouseEvent<HTMLButtonElement> — событие мыши на кнопке.

onChange

import type { ChangeEvent } from 'react';

function Input() {
    function handleChange(e: ChangeEvent<HTMLInputElement>) {
        console.log(e.target.value);
    }

    return <input onChange={handleChange} />;
}

Для <select>:

function Select() {
    function handleChange(e: ChangeEvent<HTMLSelectElement>) {
        console.log(e.target.value);
    }

    return <select onChange={handleChange} />;
}

Для <textarea>:

function Textarea() {
    function handleChange(e: ChangeEvent<HTMLTextAreaElement>) {
        console.log(e.target.value);
    }

    return <textarea onChange={handleChange} />;
}

onSubmit

import type { FormEvent } from 'react';

function Form() {
    function handleSubmit(e: FormEvent<HTMLFormElement>) {
        e.preventDefault();
        const data = new FormData(e.currentTarget);
    }

    return <form onSubmit={handleSubmit}>...</form>;
}

onKeyDown

import type { KeyboardEvent } from 'react';

function Input() {
    function handleKeyDown(e: KeyboardEvent<HTMLInputElement>) {
        if (e.key === 'Enter') {
            console.log('Enter');
        }
    }

    return <input onKeyDown={handleKeyDown} />;
}

onFocus и onBlur

import type { FocusEvent } from 'react';

function Input() {
    function handleFocus(e: FocusEvent<HTMLInputElement>) {
        console.log('focused');
    }

    return <input onFocus={handleFocus} />;
}

onMouseEnter, onMouseLeave

function Card() {
    function handleEnter(e: MouseEvent<HTMLDivElement>) {}
    function handleLeave(e: MouseEvent<HTMLDivElement>) {}

    return <div onMouseEnter={handleEnter} onMouseLeave={handleLeave} />;
}

onScroll

import type { UIEvent } from 'react';

function Scroller() {
    function handleScroll(e: UIEvent<HTMLDivElement>) {
        console.log(e.currentTarget.scrollTop);
    }

    return <div onScroll={handleScroll} />;
}

onDrag

import type { DragEvent } from 'react';

function Draggable() {
    function handleDragStart(e: DragEvent<HTMLDivElement>) {
        e.dataTransfer.setData('text', 'hello');
    }

    return <div draggable onDragStart={handleDragStart} />;
}

onTouch

import type { TouchEvent } from 'react';

function Button() {
    function handleTouch(e: TouchEvent<HTMLButtonElement>) {
        console.log(e.touches[0].clientX);
    }

    return <button onTouchStart={handleTouch}>OK</button>;
}

Inline-обработчик

Если обработчик короткий — тип можно не указывать:

<button onClick={(e) => console.log(e.clientX)}>OK</button>

TypeScript выведет тип из контекста.

currentTarget vs target

function Form() {
    function handleSubmit(e: FormEvent<HTMLFormElement>) {
        e.currentTarget; // HTMLFormElement — надёжно
        e.target;        // EventTarget | null — нужно сужать
    }
}

currentTarget — элемент, к которому привязан обработчик. target — на чём произошло событие (может быть вложенный).

Итоги

  • Типы событий из react
  • MouseEvent<T>, ChangeEvent<T>, FormEvent<T>
  • Generic T — тип элемента
  • Inline-обработчики выводят тип автоматически
  • currentTarget надёжнее target