티스토리 뷰

반응형

- 사용자가 브라우저에서 DOM 요소들과 상호 작용하는 것을 이벤트(event)라고 한다.

- 예를 들어 버튼에 마우스 커서를 올렸을 때는 onmouseover 이벤트를 실행하고, 클릭했을 때는 onclick 이벤트를 실행한다. Form 요소는 값이 바뀔 onchange 이벤트를 실행한다.

 

리액트의 이벤트 시스템

- 리액트의 이벤트 시스템은 브라우저의 HTML 이벤트와 인터페이스가 동일하기 때문에 사용법이 비슷하다.

- 다음 코드를 살펴 보자.

import { useState } from 'react';

const Say = () => {
    const [message, setMessage] = useState('');
    const onClickEnter = () => setMessage('안녕하세요!');
    const onClickLeave = () => setMessage('안녕히 가세요!');
    const [color, setColor] = useState('black');
    return(
        <div>
            <button onClick={onClickEnter}>입장</button>
            <button onClick={onClickLeave}>퇴장</button>
            <h1 style={{ color }}>{message}</h1>
            <button style= {{ color: 'red' }} onClick={() => setColor('red')}>빨간색</button>
            <button style= {{ color: 'green' }} onClick={() => setColor('green')}>초록색</button>
            <button style= {{ color: 'blue' }} onClick={() => setColor('blue')}>파란색</button>
        </div>
    );
};

export default Say;

 

이벤트를 사용할 주의 사항

1. 이벤트 이름은 카멜 표기법으로 작성한다.

 - 예를 들어 HTML onclick 리액트에서는 onClick으로 작성해야 한다.

 - onkeyup onKeyUp으로 작성한다.

 

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

 - HTML에서 이벤트를 설정할 때는 큰따옴표 안에 실행할 코드를 넣었지만, 리액트에서는 함수 형태의 객체를 전달한다.

 - 앞서 버튼 예제에서도 화살표 함수 문법으로 함수를 만들어 전달했다. 이렇게 바로 만들어서 바로 전달해도 되고, 렌더링 부분 외부에 미리 만들어서 전달해도 된다.

 

<button style= {{ color: 'green' }} onClick={() => setColor('green')}>초록색</button>

 

3. DOM 요소에만 이벤트를 설정할 있다.

 - div, button, input, form, span 등의 DOM 요소에는 이벤트를 설정할 있지만, 우리가 직접 만든 컴포넌트에는 이벤트를 자체적으로 설정할 없다.

 - 예를 들어 MyComponent onClick 값을 설정한다면 MyComponent 클릭할 doSomething 함수를 실행하는 것이 아니라, 그냥 이름이 onClick props MyComponent에게 전달해 이다.

 

<MyComponent onClick = {doSomething} />

 

 - 따라서 컴포넌트에 자체적으로 이벤트를 설정할 수는 없다. 하지만 전달받은 props 컴포넌트 내부의 DOM 이벤트로 설정할 수는 있다.

 

<div onClick = {this.props.onClick}>

{ /* (...) */ }

</div>

 

 

이벤트 종류

  • Clipboard
  • Touch
  • Composition
  • UI
  • Keyboard
  • Wheel
  • Focus
  • Media
  • Form
  • Image
  • Mouse
  • Animation
  • Selection
  • Transition

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

 

SyntheticEvent – React

A JavaScript library for building user interfaces

legacy.reactjs.org

 

 

이벤트 핸들링 연습하기

 

1. 컴포넌트 생성

- src/EventPractice.js 파일을 생성한다.

- 만든 후에 컴포넌트 초기 코드를 작성한다.

- 먼저 클래스형 컴포넌트로 작성하여 기능을 구현한다.

 

* EventPractice.js

import { Component} from 'react';

class EventPractice extends Component{
    render(){
        return(
            <div>
                <h1>이벤트 연습</h1>
            </div>
        );
    }
}

export default EventPractice;

 

2. App.js에서 EventPractice 렌더링

 

* App.js

import EventPractice from './EventPractice';

const App = () => {
    return (
        <EventPractice />
    );
}

export default App;

 

3. onChange 이벤트 설정

- EventPractice 컴포넌트에 input 요소를 렌더링하는 코드와 해당 요소에 onChange 이벤트를 설정하는 코드를 작성한다.

- 다음 코드를 EventPractice 컴포넌트의 render 메서드에 작성한다.

 

* EventPractice.js

import { Component} from 'react';

class EventPractice extends Component{
    render(){
        returnn(
            <div>
                <h1>이벤트 연습</h1>
                <input
                    type="text"
                    name="message"
                    placeholder="아무거나 입력해 보세요"
                    onChange={
                        (e) => {
                            console.log(e);
                        }
                    }
                />
            </div>
        );
    };
}

export default EventPractice;

- 코드를 저장하고, 브라우저에서 크롬 개발자 도구를 열어 인풋에 아무 것이나 입력해 보자.

- 이벤트 객체가 콘솔에 나타났다.

 

* EventPractice.js onChange 설정 부분 다시 보기

onChange={
     (e) => {
        console.log(e);
     }
}

- 여기서 콘솔에 기록되는 e 객체는 SyntheticEvent 브라우저의 네이티브 이벤트를 감싸는 객체다.

- 네이티브 이벤트와 인터페이스가 같으므로 순수 자바스크립트에서 HTML 이벤트를 다룰 때와 똑같이 사용하면 된다.

- SyntheicEvent 네이티브 이벤트와 달리 이벤트가 끝나고 나면 이벤트가 초기화되므로 정보를 참조할 없다.

- 예를 들어 0.5 뒤에 e 객체를 참조하면 e 객체 내부의 모든 값이 비워지게 된다.

- 만약 비동기적으로 이벤트 객체를 참조할 일이 있다면 e.persist() 함수를 호출해 주어야 한다.

- 에를 들어 onChange 이벤트가 발생할 , 앞으로 변할 인풋 값인 e.target.value 콘솔에 기록해 보자.

- 코드를 다음과 같이 수정해 보자.

 

* EventPractice.js onChange 코드 수정

onChange={
    (e) => {
        console.log(e.target.value);
    }
}

- 값이 바뀔 때마다 바뀌는 값을 콘솔에 기록한다.

 

state input 담기

- 이번에는 state input 값을 담아 보자.

- 생성자 메서드인 constructor에서 state 초기값을 설정하고, 이벤트 핸들링 함수 내부에서 this.setState 메서드를 호출하여 state 업데이트해 본다.

- 다음에는 input value 값을 state 있는 값으로 설정한다.

 

* EventPractice.js

import { Component} from 'react';

class EventPractice extends Component{

    state = {
        message: ''
    }


    render(){
        return(
            <div>
                <h1>이벤트 연습</h1>
                <input
                    type="text"
                    name="message"
                    placeholder="아무거나 입력해 보세요"
                    value={this.state.message}
                    onChange={
                        (e) => {
                            this.setState({
                                message: e.target.value
                            });
                        }
                    }
                />
            </div>
        );
    };
}

export default EventPractice;

- 코드를 저장하고, 인풋에 아무것이나 입력해 보자. 오류를 발생시키지 않고 제대로 입력할 있다면 state 텍스트를 담은 것이다.

 

버튼을 누를 comment 값을 공백으로 설정

- 입력한 값이 state 들어갔는지, 인풋에서 값을 제대로 반영하는지 검증해 보자.

- input 요소 코드 아래쪽에 button 하나 만들고, 클릭 이벤트가 발생하면 현재 comment 값을 메시지 박스로 띄운 comment 값을 공백으로 설정하자.

 

* EventPractice.js

import { Component} from 'react';

class EventPractice extends Component{
    state = {
        message: ''
    }


    render(){
        return(
            <div>
                <h1>이벤트 연습</h1>
                <input
                    type="text"
                    name="message"
                    placeholder="아무거나 입력해 보세요"
                    value={this.state.message}
                    onChange={
                        (e) => {
                            this.setState({
                                message: e.target.value
                            });
                        }
                    }
                />
                <button
                    onClick={() => {
                        alert(this.state.message);
                        this.setState({
                            message: ''
                        });
                    }}
                >확인</button>
            </div>
        );
    };
}

export default EventPractice;

 

 

- alert 사용하여 현재 message 값을 화면에 표시하게 했다.

 

임의 메서드 만들기

- "이벤트에 실행할 JS 코드를 전달하는 것이 아니라, 함수 형태의 값을 전달한다" 따라, 이벤트를 처리할 렌더링을 하는 동시에 함수를 만들어서 전달해 주었다.

- 방법 대신 함수를 미리 준비하여 전달하는 방법도 있다. 성능상 차이는 없지만, 가독성은 훨씬 높다.
 (
하지만 상황에 따라 렌더링 메서드 내부에서 함수를 만드는 것이 편할 때도 있다)

 

- 앞서 onChange onClick 전달한 함수를 따로 빼내서 컴포넌트 임의 메서드를 만들어 보자.

 

기본 방식

* EventPractice.js

import { Component} from 'react';

class EventPractice extends Component{
    state = {
        message: ''
    }

    constructor(props){
        super(props);
        this.handleChange = this.handleChange.bind(this);
        this.handleClick = this.handleClick.bind(this);
    }

    handleChange(e){
        this.setState({
            message: e.target.value
        });
    }

    handleClick(){
        alert(this.state.message);
        this.setState({
            message: ''
        });
    }

    render(){
        return(
            <div>
                <h1>이벤트 연습</h1>
                <input
                    type="text"
                    name="message"
                    placeholder="아무거나 입력해 보세요"
                    value={this.state.message}
                    onChange={this.handleChange}
                />
                <button
                    onClick={this.handleClick}
                >확인</button>
            </div>
        );
    };
}

export default EventPractice;

 

- 함수가 호출될 this 호출부에 따라 결정되므로, 클래스의 임의 메서드가 특정 HTML 요소의 이벤트로 등록되는 과정에서 메서드와 this 관계가 끊어져 버린다.

- 때문에 임의 메서드가 이벤트로 등록되어도 this 컴포넌트 자신으로 제대로 가리키기 위해서는 메서드를 this 바인딩(binding)하는 작업이 필요하다.

- 만약 바인딩하지 않는 경우라면 this undefined 가리키게 된다.

 

- 현재 constructor 함수에서 함수를 바인딩하는 작업이 이루어지고 있다.

 

Property Initializer Syntax 사용한 메서드 작성

- 메서드 바인딩은 생성자 메서드에서 하는 것이 정석이다.

- 하지만 방식이 불편하다고 느낄 있다. 메서드를 만들 마다 constructor 수정해야 하기 때문이다.

- 작업을 간단하게 하는 방법이 있으며, 바로 바벨의 transform-class-properties 문법을 사용하여 화살표 함수 형태로 메서드를 정의하는 것이다.

- 문법을 사용하면 코드가 어떻게 변하는지 한번 보자.

 

* EventPractice.js

import {Component} from 'react';

class EventPractice extends Component{
    state = {
        message: ''
    }
   
    handleChange = (e) => {
        this.setState({
            message: e.target.value
        });
    }
   
    handleClick = (e) => {
        alert(this.state.message);
        this.setState({
            message: ''
        });
    }

    render(){
        return(
        <div>
            <h1>이벤트 연습</h1>
            <input type="text" name="message" placeholder="아무거나 입력하세요."
            value={this.state.message}
            onChange={this.handleChange }/>
            <button onClick={this.handleClick}>확인</button>
        </div>
        );
    }
}

export default EventPractice;

- 훨씬 깔끔해졌다.

 

input 여러 다루기

- 우리는 input 값을 state 넣는 방법을 배웠다. 하지만 input 여러 개일 때는 어떻게 작업해야 하는가?

-  event 객체를 활용하며, e.target.name 값을 사용하면 된다.

- onChange 이벤트 핸들러에서 e.target.name 해당 인풋의 name 가리킨다. 지금은 message 것이다.

- 값을 사용하여 state 설정하면 쉽게 해결할 있다. 코드를 한번 살펴 보자.

- 다음 코드에서는 render 함수에서 name 값이 username input 렌더링해 주었고, state 쪽에도 username이라는 값을 추가해 주었다.

- 그리고 handleChange 조금 변경했다.

 

* EventPractice.js

import {Component} from 'react';

class EventPractice extends Component{

    state = {
        username: '',
        message: ''
    }
   
    handleChange = (e) => {
        this.setState({
            [e.target.name]: e.target.value
        });
    }
   
    handleClick = () => {
        alert(this.state.username + ': '+ this.state.message);
        this.setState({
            username: '',
            message: ''
        });
    }


    render(){
        return(
        <div>
            <h1>이벤트 연습</h1>
            <input type="text" name="username" placeholder="사용자명"
            value={this.state.username}
            onChange={this.handleChange }/>
           
            <input type="text" name="message" placeholder="아무거나 입력하세요."
            value={this.state.message}
            onChange={this.handleChange }/>
            <button onClick={this.handleClick}>확인</button>
        </div>
        );
    }
}


export default EventPractice;

 

 

- 위에서는 다음 코드가 핵심이다.

 

* EventPractice.js

handleChange = (e) => {
    this.setState({
        [e.target.name]: e.target.value
    });
}

 

- 객체 안에서 key [ ] 감싸면 안에 넣은 레퍼런스가 가리키는 실제 값이 key 값으로 사용된다.

- 예를 들어 다음과 같은 객체를 만들면

 

const name = 'variantKey';

const object = {

    [name] : 'value'

};

 

- 결과는 다음과 같다.

 

{

    'varianKey' : 'value'

}

 

 

onKeyPress 이벤트 핸들링

- 이번에는 키를 눌렀을 발생하는 KeyPress 이벤트 처리하는 방법을 알아보자.

 => 현재 onKeyPress deprecated 되었다. 따라서 onKeyDown으로 바꿔 사용한다.

- comment 인풋에서 [Enter] 눌렀을 handleClick 메서드를 호출하도록 코드를 작성한다.

 

* EventPractice.js

import {Component} from 'react';

class EventPractice extends Component{
    state = {
        username: '',
        message: ''
    }
   
    handleChange = (e) => {
        this.setState({
            [e.target.name]: e.target.value
        });
    }
   
    handleClick = () => {
        alert(this.state.username + ': '+ this.state.message);
        this.setState({
            username: '',
            message: ''
        });
    }

    handleKeyDown = (e) => {
        if(e.key === 'Enter'){
            this.handleClick();
        }
    }

    render(){
        return(
        <div>
            <h1>이벤트 연습</h1>
            <input type="text" name="username" placeholder="사용자명"
            value={this.state.username}
            onChange={this.handleChange }/>
           
            <input type="text" name="message" placeholder="아무거나 입력하세요."
            value={this.state.message}
            onChange={this.handleChange }
            onKeyDown={this.handleKeyDown}/>
            <button onClick={this.handleClick}>확인</button>
        </div>
        );
    }
}


export default EventPractice;

 

- 번째 텍스트 인풋에서 텍스트를 입력하고 [Enter] 눌러 보자. handleCLick 메서드가 실행되었는가?

 

 

함수 컴포넌트로 구현해 보기

- 페이지에서 작성한 것을 함수 컴포넌트로도 똑같이 구현할 있다. 기존 EventPractice 컴포넌트를 모두 지우고 다음과 같이 작성해 본다.

 

* EventPractice.js

import { useState } from 'react';

const EventPractice = () => {
    const [username, setUsername] = useState('');
    const [message, setMessage ] = useState('');
    const onChangeUsername = e => setUsername(e.target.value);
    const onChangeMessage = e => setMessage(e.target.value);
    const onClick = () => {
        alert(username + ': ' + message);
        setUsername('');
        setMessage('');
    };
    const onKeyDown = e => {
        if(e.key === 'Enter'){
            onClick();
        }
    };

    return(
        <div>
            <h1>이벤트 연습</h1>
            <input type="text" name="username" placeholder="사용자명" value={username} onChange={onChangeUsername} />
            <input type="text" name="message" placeholder="아무거나 입력해 보세요" value={message} onChange={onChangeMessage} onKeyDown={onKeyDown} />
            <button onClick={onClick}>확인</button>
        </div>
    );
}

export default EventPractice;

 

- 기능이 이전과 같이 작동하는가?

- 코드에서는 e.target.name 활용하지 않고 onChange 관련 함수 개를 따로 만들어 주었다.

 

- input 개밖에 없다면 이런 코드도 나쁘지는 않으나 input 개수가 많아질 같으면 e.target.name 활용하는 것이 좋을 수도 있다.

 

- 이번에는 useState 통해 사용하는 상태에 문자열이 아닌 객체 넣어 본다. 코드를 다음과 같이 수정해 본다.

 

* EventPractice.js

import { useState } from 'react';


const EventPractice = () => {
    const [form, setForm] = useState({
        username: '',
        message: ''
    });


    const { username, message } = form;
    const onChange = e => {
        const nextForm = {
            ...form,    // 기존의 form 내용을 이 자리에 복사한 뒤
            [e.target.name]: e.target.value    // 원하는 값을 덮어 씌우기
        };
        setForm(nextForm);
    }


    const onClick = () => {
        alert(username + ': ' + message);
        setForm({
            username: '',
            message: ''
        });
    };


    const onKeyDown = e => {
        if(e.key === 'Enter'){
            onClick();
        }
    };


    return(
        <div>
            <h1>이벤트 연습</h1>
            <input type="text" name="username" placeholder="사용자명" value={username} onChange={onChange} />
            <input type="text" name="message" placeholder="아무거나 입력해 보세요" value={message} onChange={onChange} onKeyDown={onKeyDown} />
            <button onClick={onClick}>확인</button>
        </div>
    );
}


export default EventPractice;

- 코드를 저장하고 기능이 작동하는지 확인해 보자.

- e.target.name 값을 활용하려면, 위와 같이 useState input 값들이 들어 있는 form 객체를 사용해 주면 된다.

반응형

'Javascript > React' 카테고리의 다른 글

[React] 리액트 state  (0) 2025.03.24
[React] 리액트 props  (0) 2025.03.13
[React] 스타일링  (0) 2025.03.06
[React] undefined 렌더링하지 않기  (0) 2025.03.06
[React] 조건부 연산자  (0) 2025.03.06
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함