'리액트를 다루는 기술' 4장, 이벤트 핸들링

Jake_Young·2020년 8월 19일
0
post-thumbnail

😁 리액트의 이벤트 시스템

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

  1. 이벤트 이름은 카멜 표기법을 따른다
  2. 이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아니라, 함수 형태의 값을 전달한다.
  3. DOM 요소에만 이벤트를 설정할 수 있다.

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

이벤트 예제 코드

import React, { Component } from "react";

export default class EventPractice extends Component {
  render() {
    return (
      <div>
        <h1>이벤트 연습</h1>
        <input
          type="text"
          name="message"
          placeholder="whatever"
          onChange={(e) => {
            console.log(e);
          }}
        />
      </div>
    );
  }
}
  • 여기서 e 객체는 SyntheticEvent로 웹 브라우저의 네이티브 이벤트를 감싸는 객체이다.
  • 네이티브 이벤트와 인터페이스가 같으므로 순수 자바스크립트에서 HTML 이벤트를 다룰 때와 똑같이 사용가능하다.
  • SyntheticEvent는 네이티브 이벤트와 달리 이벤트가 끝나고 나면 이벤트가 초기화되므로 정보를 참조할 수 없다.
  • 예를 들어, 0.5초 뒤에 e 객체를 참조하면 e 객체 내부의 모든 값이 비워진다.
  • 비동기적으로 이벤트 객체를 참조할 일이 있다면, e.persist() 함수를 호출한다.
  • 인풋값을 보려면 e.target.value를 본다.
  • 그리고 이벤트 핸들러를 inline이 아닌 형태로 쓰려면 아래와 같이 쓰면 된다.
import React, { Component } from "react";

export default 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() {
    this.setState({
      message: ""
    });
  }

  render() {
    return (
      <div>
        <h1>이벤트 연습</h1>
        <input
          type="text"
          name="message"
          placeholder="whatever"
          value={this.state.message}
          onChange={this.onChange}
        />
        <button onClick={this.onClick}>확인</button>
      </div>
    );
  }
}
  • 여기서 주의할 점은 bind(this) 부분이다.
  • 함수가 호출될 때 this는 호출부에 따라 결정되므로, 클래스의 임의 메서드가 특정 HTML 요소의 이벤트로 등록되는 과정에서 메서드와 this의 관계가 끊어져 버린다.
  • 이 때문에 임의 메서드가 이벤트로 등록되어도 this를 컴포넌트 자신으로 제대로 가리키기 위해서는 메서드를 this와 바인딩하는 작업이 필요하다.
  • 바인딩하지 않으면 this는 undefined를 가리킨다.
  • 이 바인딩 작업이 하기 싫다면 화살표 함수로 작성하면 된다.

여러 인풋을 State로 다루는 방법

import React, { Component } from "react";

export default 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="username"
          value={this.state.username}
          onChange={this.handleChange}
        />
        <input
          type="text"
          name="message"
          placeholder="message"
          value={this.state.message}
          onChange={this.handleChange}
        />
        <button onClick={this.handleClick}>확인</button>
      </div>
    );
  }
}
  • 객체 안에서 key를 [ ]로 감싸면 그 안에 넣은 레퍼런스가 가리키는 값이 key 값이 된다.
  • 그래서 e.target.name을 이용하면 state를 관리할 수 있다.

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

useState 사용 예제

import React, { useState } from "react";

const EventPracticeForFunction = () => {
  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="username"
        value={username}
        onChange={onChangeUsername}
        onKeyPress={onKeyPress}
      />
      <input
        type="text"
        name="message"
        placeholder="message"
        value={message}
        onChange={onChangeMessage}
        onKeyPress={onKeyPress}
      />
      <button onClick={onClick}>확인</button>
    </div>
  );
};

export default EventPracticeForFunction;

input 요소가 여러 개일 때 state를 객체로 다루는 법

import React, { useState } from "react";

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

  const { username, message } = form;

  const onChange = (e) => {
    const nextForm = {
      ...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="username"
        value={username}
        onChange={onChange}
        onKeyPress={onKeyPress}
      />
      <input
        type="text"
        name="message"
        placeholder="message"
        value={message}
        onChange={onChange}
        onKeyPress={onKeyPress}
      />
      <button onClick={onClick}>확인</button>
    </div>
  );
};

export default EventPracticeForFunction;
  • 나중에 useReducer나 커스텀 Hooks를 사용하면 작업을 훨씬 더 편리하게 할 수도 있다.
profile
자바스크립트와 파이썬 그리고 컴퓨터와 네트워크

0개의 댓글