리액트 이벤트
- 리액트는 가상 DOM을 다루면서 이벤트도 별도로 관리한다.
onclick
, onchange
같이 DOM 엘리먼트에 등록되는 이벤트 리스너와 달리, 리액트 컴포넌트(노드)에 등록되는 이벤트 리스너는 onClick
, onChange
처럼 카멜 케이스로 표기한다.
- 리액트 이벤트는 브라우저의 고유한 이벤트와 완전히 동일하게 동작하지 않는다. 리액트 이벤트 핸들러는 이벤트 버블링 단계에서 호출된다.
- 리액트는 브라우저 이벤트를 합성한 합성 이벤트(SyntheticEvent)를 제공한다.
| type EventHandler<Event extends React.SyntheticEvent> = ( |
| e: Event |
| ) => void | null; |
| type ChangeEventHandler = EventHandler<ChangeEvent<HTMLSelectElement>>; |
| |
| const eventHandler1: GlobalEventHandlers['onchange'] = (e) => { |
| |
| console.log(e.target); |
| }; |
| |
| const eventHandler2: ChangeEventHandler = (e) => { |
| |
| console.log(e.target); |
| }; |
- 리액트의 SyntheticEvent을 사용하면 이벤트 핸들러의 타입을 지정할 수 있다.
| const Select = () => { |
| const handleChange: React.ChangeEventHandler<HTMLSelectElement> = (e) => { |
| |
| }; |
| |
| return <select onChange={handleChange}></select>; |
| }; |
제네릭 컴포넌트
- 함수 컴포넌트도 함수이므로 제네릭을 사용한 컴포넌트를 구현할 수 있다. 제네릭을 지정한 뒤 props를 넘겨주면 타입을 자동으로 추론해준다.
| interface SelectProps<OptionType extends Record<string, string>> { |
| options: OptionType; |
| selectedOption?: keyof OptionType; |
| onChange?: (selected?: keyof OptionType) => void; |
| } |
| |
| const Select = <OptionType extends Record<string, string>>({ |
| options, |
| selectedOption, |
| onChange, |
| }: SelectProps<OptionType>) => { |
| return <></>; |
| }; |
| |
| const fruits = { |
| apple: '사과', |
| banana: '바나나', |
| blueberry: '블루베리', |
| }; |
| |
| const FruitSelect = () => { |
| |
| return <Select options={fruits} selectedOption="apple" />; |
| }; |
HTMLAttributes
className
, id
와 같은 리액트 컴포넌트의 기본 props를 추가할 때 직접 추가해줘도 되지만 리액트에서 제공하는 타입을 사용하면 더 정확한 타입을 설정할 수 있다.
- ComponentPropsWithoutRef는 리액트 컴포넌트에서 ref를 제외한 prop 타입을 반환해준다.
- Pick 유틸리티 타입을 통해 ReactProps에서 여러 개의 속성 타입을 가져올 수 있다. 이를 통해 인터페이스를 확장해준다.
| type ReactSelectProps = React.ComponentPropsWithoutRef<'select'>; |
| |
| interface SelectProps<OptionType extends Record<string, string>> |
| extends Pick<ReactSelectProps, 'id' | 'className'> { |
| options: OptionType; |
| selectedOption?: keyof OptionType; |
| onChange?: (selected?: keyof OptionType) => void; |
| } |