티스토리 뷰

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

4.1 리액트의 이벤트 시스템

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

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

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

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

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

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

DOM 요소에는 이벤트를 설정할 수 있지만 직접 만든 컴포넌트에는 이벤트를 자체적으로 설정할 수 없다.

컴포넌트에 이벤트를 설정한다면 이벤트를 실행하는 것이 아니라 props를 컴포넌트에 전달해 줄 뿐이다.

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

 

4.1.2 이벤트 종류

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

https://facebook.github.io/react/docs/events.html 참고

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

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

> onKeyPress 이벤트 핸들링하기

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

4.2.1.1 컴포넌트 생성

컴포넌트 초기 코드 작성. 클래스형 컴포넌트로 작성

4.2.1.2  App.js에서 EventPractice 렌더링

4.2.2 onChange 이벤트 핸들링하기

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로 웹 브라우저의 네이티브 이벤트를 감싸는 객체이다. 네이티브 이벤트와 인터페이스가 같으므로 순수 자바스크립트에서 HTML 이벤트를 다룰때와 똑같이 사용하면 된다.

 

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

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

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

4.2.2.2 state에 input 값 담기

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

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;

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

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

<button
          onClick={() => {
            alert(this.state.message);
            this.setState({ message: "" });
          }}
        >
          확인
        </button>

4.2.3 임의 메서드 만들기

이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아니라, 함수 형태의 값을 전달한다. 그렇기 때문에 이벤트를 처리할 때 렌더링을 하는 동시에 함수를 만들어서 전달해 준다. (또는 함수를 미리 준비하여 전달하는 방법) 성능상으로는 차이가 거의 없지만, 가독성은 훨씬 높다. (하지만 상황에 따라 렌더링 메서드 내부에서 함수를 만드는 것이 더 편할 때도 있다.)

4.2.3.1 기본 방식

함수가 호출될 때 this는 호출부에 따라 결정되므로, 클래스의 임의 메서드가 특정 HTML 요소의 이벤트로 등록되는 과정에서 메서드와 this의 관계가 끊어져 버린다. 이때문에 임의 메서드가 이벤트로 등록되어도 this를 컴포넌트 자신으로 제대로 가리키기 위해서는 메서드를 this와 바인딩하는 작업이 필요하다. 만약 바인딩하지 않는 경우라면 this가 undefined를 가리키게 된다.

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

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;

4.2.3.2 Property Initialzer Syntax를 사용한 메서드 작성

메서드 바인딩은 생성자 메서드에서 하는 것이 정석이다. 하지만 이 작업을 불편하다고 느낄 수 있다. 새 메서드를 만들때마다 constructor도 수정해야 하기 때문이다. 이 작업을 좀 더 간단하게 하는 방법이 있다.

바로 바벨의 transform-class-properties 문법을 사용하여 화살표 함수 형태로 메서드를 정의하는 것이다.

import React, { Component } from "react";

class EventPractice extends Component {
  state = {
    message: "",
  };
  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;

4.2.4 input 여러 개 다루기

event 객체를 활용하는 방법

e.target.name 값을 사용하면 된다. onChange 이벤트 핸들러에서 e.target.name은 해당 인풋의 name을 가리킨다. 이 값을 사용하여 state를 설정하면 쉽게 해결할 수 있다.

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;

4.2.5 onKeyPress 이벤트 핸들링

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: "",
    });
  };
  handleKeyPress = (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}
          onKeyPress={this.handleKeyPress}
        />
        <button onClick={this.handleClick}>확인</button>
      </div>
    );
  }
}
export default EventPractice;

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

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을 활용하지 않고 onChange 관련 함수 두 개를 따로 만들어 주었다.

인풋 개수가 많아질 것 같으면 e.target.name을 활용하는 것이 더 좋을 수도 있다.

 

문자열이 아닌 객체 넣기

import React, { 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 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.4 정리

리액트에서 이벤트를 다루는 것은 순수 자바스크립트 또는 jQuery를 사용한 웹 애플리케이션에서 이벤트를 다루는 것과 비슷하다. 리액트의 장점 중 하나는 자바스크립트에 익숙하다면 쉽게 활용할 수 있다는 것이다. 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
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
글 보관함