[React] 이벤트 시스템 (Event)

🌊·2021년 12월 7일
0

React

목록 보기
4/20

이벤트 시스템

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

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

  1. 이벤트 이름은 카멜 표기법으로 작성한다
    (ex. HTML의 onclick은 리액트에서 onClick으로 작성해야 한다.)

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

    화살표 함수 문법으로 함수를 만들어서 전달해도 된다.
    가독성을 위해서 렌더링 부분 외부에 미리 만들어서 호출해주는 방식으로 전달하는게 좋을 것 같다.

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

    div, button, input,form, span 등에는 이벤트를 설정할 수 있지만, 직접 만든 컴포넌트에는 이벤트를 자체적으로 설정할 수 없다.

이벤트 종류

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

이벤트 핸들링

컴포넌트 생성 및 불러오기 -> onChange 이벤트 핸들링하기 -> 임의 메서드 만들기 -> input 여러 개 다루기 -> onKeyPress 이벤트 핸들링하기

컴포넌트 생성 및 불러오기

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

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

export default EventPractice;


import EventPractice from "./EventPractice"; // App.js

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

export default App;

이벤트 핸들링

<input
  type="text"
  name="message"
  placeholder="아무거나 입력해 보세요"
  onChange={(e) => {
    console.log(e.target.value);
  }}
/>

input 요소를 렌더링하고 요소에 onChange 이벤트를 핸들링하는 코드를 작성한다.
e 객체는 SyntheticEvent로 웹 브라우저의 네이티브 이벤트를 감싸는 객체이다.
onChange 이벤트가 발생할 때 앞으로 변할 인풋 값 == (e.target.value)

state에 input 값 담기

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

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>
    );
  }
}

임의 메서드 만들기

렌더링 할 때 함수를 만들어서 전달해주는 것과 미리 메서드를 만들어서 전달하는 방식은 성능상 차이는 거의 없다.
미리 메서드를 만들어서 전달하는 방식이 가독성은 훨씬 높다.

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;

임의 메서드가 호출될 때 this는 호출부에 따라 결정되므로 임의 메서드가 HTML 요소의 이벤트로 등록되는 과정에서 메서드와 this 관계가 끊어진다.
임의 메서드가 이벤트로 등록되어도 this를 컴포넌트 자신으로 가리키기 위해서 메서드와 this를 바인딩this.handleChange.bind(this)하는 작업이 필요하다.
바인딩하지 않으면 this가 undefined를 가리키게 된다.

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

메서드 바인딩은 생성자 메서드(constructor)에서 하는 것이 정석이다.
하지만 메서드를 만들 때마다 constructor도 수정해야 하는 불편함이 있다.
이 작업을 더 간단하게 하기 위해서 바벨의 transform-class-properties 문법을 사용하여 화살표 함수 형태로 메서드를 정의하면 된다.

// 적용 전 메서드 정의
handleChange(e) {
  this.setState({
    message: e.target.value,
  });
}

// 적용 후 메서드 정의
handleChange = (e) => {
  this.setState({
    message: e.target.value,
  });
};

메서드와 this를 바인딩하지 않아도 된다. (this.handleChange.bind(this)를 사용하지 않아도 된다)
생성자 메서드(constructor)를 따로 사용하지 않아도 된다.

동일한 메서드로 input 여러 개 다루기

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

<input type="text" name="username" placeholder="사용자명" onChange={this.handleChange} value={this.state.username} />
<input type="text" name="message" placeholder="아무거나 입력해보세요" onChange={this.handleChange} value={this.state.message} />

객체 안에서 key를 []로 감싸면 그 안에 넣은 레퍼런스가 가리키는 값이 key 값으로 사용된다.
첫 번째 input의 경우에는 메서드가 호출되고 { username: e.target.value(입력 받은 값 } 이 된다.
두 번째 input의 경우 { message: e.target.value } 이 된다.

onKeyPress 이벤트 핸들링

키를 눌렀을 때 발생하는 keyPress 이벤트를 처리할 수 있다.

handleKeyPress = (e) => {
  if (e.key === "Enter") {
    this.handleClick();
  }
};


<input type="text" name="message" placeholder="아무거나 입력해보세요" onKeyPress={this.handleKeyPress} onChange={this.handleChange} value={this.state.message} />

두 번째 input 요소에 focus가 되어있을 때 Enter를 누르면 handleKeyPress 메서드가 실행된다.

함수 컴포넌트로 변경하기

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;

0개의 댓글