[React]리액트를 다루는 기술-4. 이벤트 핸들링

chaaerim·2021년 11월 14일
4
post-thumbnail

📖 이벤트 핸들링

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

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

리액트의 이벤트 시스템은 웹 브라우저의 HTML 이벤트와 인터페이스가 동일하다.

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

  1. 이벤트 이름은 카멜 표기법으로 작성.
    -ex) onclick -> onClick, onkeyup->onKeyUp
  2. 이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아니라, 함수 형태의 값을 전달.
    -화살표 함수 문법을 사용하거나 렌더링 부분 외부에 미리 만들어서 전달.
  3. DOM 요소에만 이벤트를 설정할 수 있다.
    -div, button, input, form, span등의 DOM 요소에는 이벤트를 설정할 수 있지만, 직접 만든 컴포넌트에는 이벤트를 자체적으로 설정 불가.
    ex) <MyComponent onClick={doSomething}/> 이와 같이 MyComponent에 onClick값을 설정하면, onClick인 props를 MyComponent에 전달해줄 뿐.

4.1.2. 이벤트 종류

리액트에서 지원하는 이벤트는 다음을 참고하길 바란다.
이벤트 리액트 매뉴얼 참고


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

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

의 순서로 공부해보겠습니다!

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

✍ example

//EventPractice.js
import { Component } from "react";
class EventPractice extends Component{
  render(){
      return(
          <div>
              <h1>이벤트 연습</h1>
          </div>
      );
  }
}
export default EventPractice;
//App.js
import EventPractice from './EventPractice';

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

export default App;

✔ 결과 확인

4.2.2. onChange 이벤트 핸들링하기

✍ example

import { 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;
  • EventPractice 컴포넌트에 input 요소를 렌더링 하는 코드와 onChange 이벤트 설정.

✔ 결과 확인

  • 이벤트 객체가 콘솔에 나타남.

✍ example

  onChange={
               (e)=>{
                 console.log(e);
               }
                }
  • 콘솔에 기록되는 e 객체는 SyntheticEvent로 웹 브라우저의 네이티브 이벤트를 감싸는 객체.
  • SyntheticEvent는 네이티브 이벤트와 달리 이벤트가 끝나면 이벤트가 초기화.
  • 따라서 비동기적으로 이벤트 객체를 참조할 일이 있다면 e.persist()함수를 호출해야 함.


🧐 만약 값이 변할 때마다 인풋 값을 콘솔에 기록하고 싶다면?
✍ example

    onChange={
         (e)=>{
          console.log(e.target.value);
              }
                }
  • e.target.value를 이용.


✔ 결과 확인

4.2.2.2. state에 input 값 담기

✍ example

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={message:''}state을 constructor에서 꺼내서 초깃값을 설정.
  • this.setState를 호출하여 state 업데이트.
  • value={this.state.message} input의 value값을 state에 있는 값으로 설정.

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

✍ example

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;
  • button 태그에서 alert을 이용하여 현재 state값을 경고창으로 보여줌.
  • comment값을 보여준 다음 값을 공백으로 설정.

✔ 결과 확인

4.2.3. 임의 메서드 만들기

이벤트에 실행할 자바스크립트 코드를 전달하는 것이 아니라, 함수 형태의 값을 전달한다.
1. 이벤트를 처리할 때 렌더링을 하는 동시에 함수를 만들어서 전달하기.
2. 함수를 미리 준비하여 전달하는 방법

4.2.3.1. 기본 방식

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

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를 컴포넌트 자신으로 제대로 가리키기 위해서는 메서드를 this와 바인딩하는 작업이 필요. (this.handleChange.bind(this)) ❗ 만약 바인딩하지 않는다면 this가 undefined를 가리키게 됨.

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

메서드 바인딩은 생성자 메서드에서 하는 것이 정석이다. 그러나 새 메서드를 만들 때마다 constructor도 수정해야하므로 불편하다. 이를 더 간단하게 표현하는 방법을 알아보자!

✍ example

import { 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;
  • 바벨의 transform-class-properties 문법을 사용하여 작성한 코드.
  • 화살표 함수 형태로 메서드를 정의하여 간단하게 표현 가능.

4.2.4. input 여러 개 다루기

event 객체를 활용해서 input을 여러 개 다뤄보자. (input 여러 개를 처리하기 위해서 메서드를 여러개 만들 필요가 없다! )
✍ example

import { Component } from "react";
class EventPractice extends Component{
    state={
        message:'',
        username:''
    }

  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;  
  • e.target.name을 사용해서 각각의 input에 맞는 값으로 state에 삽입. (각각의 input마다 name이 다르므로 ! )
  • 객체 안에서 key를 [ ]로 감싸면 그 안에 넣은 레퍼런스가 가리키는 실제 값이 key 값으로 사용됨.
    ex) [e.target.name]:e.target.value에서 [e.target.name]은 곧 "username"이나 "message"

✔ 결과 확인

4.2.5. onKeyPress 이벤트 핸들링

✍ example

    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>
        );
    }
  • Enter키를 눌렀을 때 handleClick메서드를 호출할 수 있게끔 handleKeyPress 메서드 추가.

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

useState을 통해 사용하는 상태에 문자열이 아닌 객체를 넣어보자.

✍ example

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 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;
  • const[form, setForm]=useState({ });에서 form은 객체의 현 상태, setForm은 상태를 바꿔주는 함수.

  • 기존의 form 내용을 복사하고 원하는 값으로 덮어 씌우는 작업 필요

    • 여기서 사용한 ... 문법은 spread 문법. 이는 객체의 내용을 모두 "펼쳐서" 기존 객체를 복사.

    • 이러한 작업을, "불변성을 지킨다" 라고 함. 불변성을 지켜주어야만 리액트 컴포넌트에서 상태가 업데이트가 됐음을 감지 할 수 있고 이에 따라 필요한 리렌더링이 진행.
      ✅ 리액트에서 객체를 업데이트하게 될 때에는 기존 객체를 직접 수정하면 안되고, 새로운 객체를 만들어서, 새 객체에 변화를 주어야 한다!!

      더 자세한 설명은 링크를 참고하세요.

✔ 마치며

다음 포스팅에서는 ref에 대해 공부하고 실습해보겠습니다.😃

0개의 댓글