본문 바로가기

Computer Programming/[리액트를 다루는 기술]

[리액트를 다루는 기술] 4. 이벤트 핸들링

리액트를 다루는 기술 - 김민준

4. 이벤트 핸들링

 

DOM의 Event (문자열로 전달)

<button onclick="activate()">
    Activate
</button>

리액트의 Event (함수 그대로를 전달)

<button onClick={activate}>
    Activate
</button>

 

<용어정리>

이벤트 : 사용자가 웹 브라우저에서 DOM 요소들과 상호작용 하는 것

이벤트 핸들러란? 이벤트가 발생하면 처리하는 역할

 

 

이벤트 사용시 주의사항

1. 카멜표기법

2. 실행할 자바스크립트 코드를 전달하는 것이 아니라, 함수 형태의 값(객체 자체)을 전달해야한다.

3. DOM 요소에만 이벤트를 설정할 수 있음 : 즉, 우리가 만든 컴포넌트에는 이벤트를 설정할 수 없고 DOM 요소인 div, button, span, form등에만 설정할 수 있다. 우리가 만든 컴포넌트에 onClick = {clickHandler} 을 설정한다면 단지 onClick이라는 이름의 prop을 전달하는 것으로 간주한다.

 

<input
    type="text"
    name="message"
    placeholder="text me"
    onChange={(e) => {
        console.log(e)
    }}
/>

 

인풋 태그 내 onChange 이벤트핸들러를 작성하고 텍스트를 입력하면 e 객체가 콘솔에 찍히는데, SyntheticEvent라고 한다. (합성이벤트)

 

이는 모든 브라우저에서 이벤트를 동일하게 처리하기 위한 이벤트 래퍼이다. 브라우저 종류마다 다른 고유이벤트는 nativeEvent 라고 한다. 리액트는 네이티브 이벤트와 동일한 인터페이스를 가지면서 이 합성 이벤트를 정의하기 때문에 브라우저 호환성을 걱정하지 않아도 된다(크로스 브라우징). 

https://ko.legacy.reactjs.org/docs/events.html

 

 

4.2.3 버튼을 누르면 input 값을 띄우고 공백으로 클리어

import { useState } from "react"

const EventPractice = () => {

    const [state,setState] = useState('')

    const clickHandler = (e) => {
        alert(state)
        setState('') //공백으로 초기화
    }

    const changeHandler = (e) => {
        setState(e.target.value)
    }

    return (
        <div className="eventPractice">
            <h1>이벤트 연습</h1>
            <input
                type="text"
                name="message"
                placeholder="text me"
                value = {state}
                onChange={changeHandler}
            />
            <button onClick={clickHandler}>
                확인
            </button>
        </div>
    )
}

export default EventPractice

 

 

4.2.4 여러개의 인풋으로 state를 저장하려면 e.target.name 으로 함수를 하나만 만들어서 재사용할 수 있음

 

원래 책에는 class형으로 나와있는데 함수형이 더 익숙해서 함수형으로 바꿔보았다. 근데 인풋 두개 중 마지막 하나만 state에 담겨서 계속 고민했다. 알고보니 setState 을 할 때 스프레드 연산으로 복사해야 했는데 그걸 안해서 문제였다.

 

스프레드연산을 하지 않는다면 배열의 복사가 이루어지는 것이 아니라 같은 참조값을 가지게 되어 원본도 같이 수정되는 문제가 생긴다.

 

setState({...state, [e.target.name]: e.target.value})

이렇게 스프레드 연산을 통해 새로운 참조값을 가진 오브젝트를 새로 만들어줘야한다. 그 오브젝트가 변경된 내용물을 가지게 되고 불변성을 유지한다.

 

그러나 spread operator은 값을 복사할 때 얕은 복사를 하게 되므로 가장 바깥쪽에 있는 값만 복사된다. 객체 안의 변수에 또 객체가 담겨있다면 그 내부의 값도 또한 복사해주어야 한다. 이때는 immer 라이브러리를 통해 불변성을 관리해주면 된다.

 

 

(근데 책을 3장 넘기니까 함수형코드가 나와있었음 ㅎㅎ^^)

 

import { useState } from "react"

const EventPractice = () => {

    const [state,setState] = useState({
        username: '',
        message: '',
    })

    const handleChange = (e) => {
        setState({...state, [e.target.name] : e.target.value})
        console.log(state)
    }

    const handleClick = () => {
        console.log(state)
        alert(state.username, state.message)
        setState({
            username: '',
            message: '',
        })
    }

    return (
        <div className="eventPractice">
            <h1>이벤트 연습</h1>
            <input
                type="text"
                name="username"
                placeholder="user name"
                value = {state.username}
                onChange={handleChange}
            />
            <input
                type="text"
                name="message"
                placeholder="message"
                value = {state.message}
                onChange={handleChange}
            />
            <button onClick={handleClick}>
                확인
            </button>
        </div>
    )
}

export default EventPractice

 

 

+추가: 객체에서 key 값 접근하기

setState({...state, [e.target.name] : e.target.value})

 

- handleKeyPress() 

    const handleKeyPress = (e) => {
        e.key === "Enter" && handleClick()
    }

조건문을 사용해 enter 키 일 경우 click() 핸들러와 같은 함수를 실행시킴 => ux 향상