상세 컨텐츠

본문 제목

<리액트를 다루는 기술> 4장: 이벤트 핸들링

21-22/21-22 리액트 스타터 -2

by dev otcroz 2021. 11. 15. 13:00

본문

728x90

INDEX

4장 이벤트 핸들링

1. 리액트의 이벤트 시스템

1.1 이벤트를 사용할 때 주의 사항

1.2 이벤트 종류

2. 예제로 이벤트 핸들링 익히기

2.1 컴포넌트 생성 및 불러오기

2.2 onChange 이벤트 핸들링하기

2.3 임의 메서드 만들기

2.4 input 여러 개 다루기

2.5 onKeyPress 이벤트 핸들링

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

4. Question 개념 정리 및 코드 문제

● 개념 복습 문제

● 코드 문제


이벤트 핸들링

이벤트(event): 사용자가 웹 브라우저에서 DOM 요소들과 상호작용하는 것으로 클릭, 키보드 입력 등의 사용자의 행위

이벤트 핸들링: 이벤트(event)를 처리하는 것

 

자바스크립트의 이벤트 실행

<!DOCTYPE html>
<html>
<head>
  <meta charset=“utf-8“>
  <meta name=“viewport“ content=“width=device-width“>
  <title>JS Bin</title>
</head>
<body>
  <button onclick=“alert(‘executed‘)“>
    Click Me
  </button>
</body>
</html>

위의 코드를 웹 브라우저에서 렌더링하면 다음과 같이 실행된다.


1. 리액트의 이벤트 시스템

// Say.js
import React, { 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;

위 코드는 3장에서 다루었던 버튼 코드(Say.js)이다.


1.1  이벤트를 사용할 때 주의사항

  • 이벤트 이름은 카멜표기법으로 표기한다.  ex) onclick -> onClick
  • 이벤트를 설정할 때 함수 형태의 값을 전달한다.
  • DOM 요소(html, button, input, form 등)에만 이벤트를 설정할 수 있다. 즉, 직접 만든 컴포넌트에는 이벤트를 설정할 수 없다.

컴포넌트에 자체적으로 이벤트를 설정할 수 없다.

// App.js
<MyComponent onClick={doSomething}/>
// onClick인 props를 Myconponent에 전달

전달받은 props를 컴포넌트 내부의 DOM 이벤트로 설정할 수 있다.

// 컴포넌트.js
<div onClick={this.props.onClick}>
    { /* (…) */ }
</div>

1.2  이벤트 종류

리액트에서 지원하는 이벤트 종류

나머지 이벤트는 리액트 매뉴얼(https://facebook.github.io/react/docs/event.html)을 참고

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

2. 예제로 이벤트 핸들링 익히기

 


2.1  컴포넌트 생성 및 불러오기

① EventPractice 컴포넌트 생성

// EventPractice.js
import React, { Component } from 'react';


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

export default EventPractice;

② App.js에서 EventPractice 렌더링

// App.js
import React from 'react';
import EventPractice from './EventPractice';
 
const App = () => {
return <EventPractice />;
};
 
export default App;

 


2.2  onChange 이벤트 핸들링하기

① onChange 이벤트 설정

<input> 태그를 추가, 태그 내에 onChange 이벤트를 설정하였다.

이때 이벤트를 설정할 때, 함수 형태의 값으로 설정한다.

// EventPractice.js
import React, { Component } from 'react';

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

export default EventPractice;

e 객체: SyntheticEvent(합성 이벤트), 웹 브라우저의 네이티브 이벤트(고유 이벤트)를 감싸는 객체

# SyntheticEvent: 이벤트 핸들링을 할 때, 모든 브라우저에서 이벤트를 동일하게 처리하기 위해 받는 객체

# 네이티브 이벤트: 브라우저의 고유 이벤트

 

*출처: React 문서 - 합성 이벤트: https://ko.reactjs.org/docs/events.html 

 

② onChange 코드 수정

e.target.value: 이벤트가 발생할 때마다 이벤트가 발생하는 target의 value

console.log(e.target.value): 이벤트가 발생할 때마다 e.target.value를 콘솔 출력

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

input의 value가 바뀔 때마다 console.log()가 실행&amp;amp;amp;amp;amp;amp;amp;nbsp;

③ state에 input 담기

state 객체를 선언 및 정의: state 초깃값 설정

input의 value값에서 state 사용

onChange 이벤트가 발생할 때 setState()를 수행

import React, { 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;

위의 사진과 같은 결과가 나온다.

 

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

input 요소에 button을 생성

button에 onClick 이벤트가 발생, alert를 통해 현재 message값을 출력 후 setState()를 통해 message 값 공백으로 설정

import React, { Component } from ‘react‘;

class EventPractice extends Component {

state = {
    message: ''
  }

render() {
    return (
      <div>
        <h1>이벤트 연습</h1>
        <input
          (…)
        />
        <button onClick={
          () => {
            alert(this.state.message);
            this.setState({
              message: ''
            });
          }
        }>확인</button>
      </div>
    );
  }
}

export default EventPractice;


2.3  임의 메서드 만들기

이벤트를 설정할 때 함수 형태의 값을 전달한다.

① 기본 방식

위의 코드를 메서드를 만들어서 다시 작성하였다.

bind(this): 메서드와 this 관계가 끊어지지 않도록 함. 임의 메서드에서 이벤트가 발생해도 this가 컴포넌트를 가리키게 하는 작업

# 바인딩: 프로그램에 사용된 요소에 속성을 연결하는 과정

// EventPractice.js
import React, { 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;

 

② Property Initializer Syntax를 사용한 메서드 작성

메서드를 만들 때마다 생성자 메서드(constructor)를 수정해야 하는 불편함

화살표 함수 형태로 메서드 작성

 

// EventPractice.js
import React, { Component } from 'react';
 
class EventPractice extends Component {
 
  state = {
    message: ''
  }
  
  //constructor 삭제
 
  handleChange = (e) => { // 화살표 함수로 수정
    this.setState({
      message: e.target.value
    });
  }
 
  handleClick = () => { // 화살표 함수로 수정
    alert(this.state.message);
    this.setState({
      message: ''
    });
  }
 
 //...
 
export default EventPractice;

2.4  input 여러 개 다루기

event.target.name: 이벤트가 발생했을 때의 target의 이름

import React, { 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의 handleChange 함수

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

 

객체 내의 key 값을 [ ](대괄호)로 둘러싸면 안에 넣은 레퍼런스가 가리키는 실제 값이 key로 사용 

const name = ‘variantKey‘;
const object = {
[name]: ‘value‘
};
{
‘variantKey‘: ‘value‘
}

2.5  onKeyPress 이벤트 핸들링

onKeyPress: 키를 눌렀을 때 발생하는 이벤트

handKeyPress 메서드 추가, input에서 onKeyPress에 대한 이벤트 설정

import React, { Component } from 'react';
 
class EventPractice extends Component {
 
//...
 
  handleKeyPress = (e) => {
    if(e.key === 'Enter') {
      this.handleClick();
    }
  }
 
  render() {
    return (
      <div>
        //...
        <input
          type="text"
          name="message"
          placeholder="아무거나 입력해 보세요"
          value={this.state.message}
          onChange={this.handleChange}
          onKeyPress={this.handleKeyPress}
        />
        <button onClick={this.handleClick}>확인</button>
      </div>
    );
  }
}
 
export default EventPractice;

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

이 코드에서는 e.target.name을 사용하지 않고 onChange 관련 메서드를 따로 생성

input 개수가 많아질수록 e.target.name을 활용하는 것이 좋다.

// EventPractice.js
import React, { 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 onKeyPress = 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}
        onKeyPress={onKeyPress}
      />
      <button onClick={onClick}>확인</button>
    </div>
  );
};
export default EventPractice;

 

▶ 수정 코드 - e.target.name 활용하기

userState 상태값에 문자열이 아닌 객체를 넣는다.

import React, { useState } from 'react';
 
const EventPractice = () => {
  const [form, setForm] = useState({ // 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 onKeyPress = 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} /*/
        onKeyPress={onKeyPress}
      />
      <button onClick={onClick}>확인</button>
    </div>
  );
};
export default EventPractice;

4. Question 개념 정리 및 코드 문제

● 개념 복습 문제

1. 사용자가 웹 브라우저에서 DOM 요소와 상호작용하는 것을 ( 이벤트 )(이)라고 하며, 이를 처리하는 것을 ( 이벤트 핸들링 )(이)라고 한다.

2. 리액트에서 이벤트를 사용할 때 주의사항이다. 이벤트의 이름은 ( 카멜표기법 )을/를 따라야 하며, 이벤트를 설정할 때 ( 함수 ) 형태의 표기법을 따른다.

3. ( bind ) 함수는 호출하는 메서드와 this가 가리키는 값이 끊어지지 않도록 하는 메서드로, 이벤트가 발생해도 컴포넌트를 가리키도록 설정한다.

4. ( e.target.name )은/는 이벤트가 발생했을 때 이벤트가 발생한 타겟의 이름을 의미하는 코드로, 이벤트를 처리할 때 자주 사용하는 코드이다.

5. 객체 내의 key 값을 (  [ ](대괄호)  )(으)로 둘러싸면 안에 넣은 레퍼런스가 가리키는 실제 값이 key로 사용된다.

6. 키를 입력했을 때 발생하는 이벤트를 ( onKeyPress )(이)라고 한다.

7. 함수형 컴포넌트에서 event.target.name을 사용할 때 useState의 상태값에 문자열이 아닌 ( 객체 )을/를 넣는다.

● 코드 문제

1. onChange 이벤트 핸들링하기: input의 값이 바뀔때마다 콘솔창에 input의 value값이 출력되도록 코드 작성

// 4_pratice_1.js
import React, { Component } from 'react';

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

export default EventPractice;

2. 코드 작성하기

(1) Property Initializer Syntax를 사용한 메서드 작성 : 생성자 메서드를 삭제하고 각 메서드들을 화살표 함수로 바꾸기

(2) 2번째 input에서 Enter을 누르면 onKeyPress 이벤트 발생: onKeyPress 메서드(handleKeyPress)를 구현, 메서드 내에 Enter을 입력했을 때 handleClick() 메서드를 실행하도록 코드를 작성한다.

// 4_pratice_2.js
import React, { Component } from 'react';

class EventPractice extends Component {

state = {
    username: '',
    message: ''
  }

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

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

handleClick(){
    alert(this.state.username + ': ' + this.state.message);
    this.setState({
      username: '',
      message: ''
    });
  }
  
  //handleKeyPress 함수 구현

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}
          onKeyPress={this.handleKeyPress} //onKeyPress 발생 시 handleKeyPress 메서드 호출
        />
        <button onClick={this.handleClick}>확인</button>
      </div>
    );
  }
}

export default EventPractice;

Corner React Starter #2

Editor 유숨숨

728x90

관련글 더보기