Event Handling

Haechan Kim·2022년 1월 8일
0

React

목록 보기
4/13
post-thumbnail
  • 이벤트(event): 사용자가 웹 브라우저에서 DOM요소들과 상호작용 하는것
    마우스의 onmouseover, onclick, Form의 onchange 등등
    html에서 DOM요소에 이벤트 설정하는것과 비슷

html에서는 이벤트 실행하면 " " 사이에 있는 js 코드 실행됨.

<button onclick = "alert('버튼 클릭!')">클릭하세요</button>

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

  • 주의 사항
  1. 이벤트의 이름은 Camel Casing
    html의 onclick은 리액트에서 onClick으로 작성

  2. 이벤트에 실행할 js 코드를 전달하는 것이 아닌 함수 형태 값을 전달
    html에서는 ""안에 실행할 코드 넣었지만 리액트에서는 함수 형태의 객레 전달.

  1. DOM 요소에만 이벤트 설정 가능
    div, button, form, span 등의 DOM 요소에는 이벤트 설정할 수 있지만 직접 만든 MyComponent등의 컴포넌트에는 이벤트 자체적으로 설정 X
    MyComponent에 onClick값 설정하면 클릭시 함수 실행하는것이 아니라 그냥 이름이 onClick인 props를 전달해줄 뿐이다.
<MyComponent onClick = {doSomething}/>

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

<div onClick = {this.props.onClick}/>
	{ ~ }
  • onChange 이벤트 설정
    input요소를 렌더링하는 코드와 해당 요소에 onCHange 이벤트 설정 코드
class EventPractice extends Component {
  render() {
    return (
      <div>
        <h1>이벤트 연습</h1>
        <input
          type=“text“
          name=“message“
          placeholder=“아무거나 입력해 보세요“
          onChange={
            (e) => {
              console.log(e.target.value);
            }
          }
        />
      </div>
    );
  }
}
  • state에 input값 넣기
    state 값을 초기에 설정하고 이벤트 핸들링 함수 내부에서 this.setState 메서드를 호출하여 state를 업데이트
import React, {Component} from 'react';

class EventPractice extends Component {

    state = { // state 초깃값 설정
        message: ''
    }

    render() {
        return (
            <div>
                <h1>이벤트 연습</h1>
                <input
                type = "text"
                name = 'message'
                placeholder = 'enter anything'

                value = {this.state.message}

                onChange = {
                    (e) => {
                        this.setState({
                            message: e.target.value
                        })
                    }
                } 
                />
		// 입력한 값이 state에 잘 들어갔는지 확인
                <button onClick = {
                    () => {
                        alert(this.state.message);
                        this.setState({
                            message: ''
                        });
                    }
                }>확인</button>
            </div>
        )
    }
}

export default EventPractice;

주의 사항에서 이벤트에 함수 형태의 값을 전달한다고 했다.
그렇기에 이벤트 처리 시 렌더링 동시에 함수 만들어서 전달했음
그 대신 미리 함수 미리 전달하는 방법 쓰면 가독성 높다
onChange, onClick에 전달한 함수 따로 빼서 컴포넌트 임의 메서드 만들기

class EventPractice extends Component {

    state = {
        message: ''
    }

    constructor(props) { // 함수 바인딩 작업
        super(props);
        this.handleChange = this.handleChange.bind(this); // 메소드에 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 = 'enter anything'

                value = {this.state.message}

                onChange = {this.handleChange}
                />

                <button onClick = {this.handleClick}>확인</button>
            </div>
        )
    }
}

메서드 바인딩은 생성자 메서드에서 하는것이 정석
but 새 메서드 만들 때마다 constructor 수정해야 함
바벨의 transform-class-properties 문법 사용해 화상표 함수 형태로 간단히 가능

// constructor 없음
state = {
    message: ''
}

handleChange = (e) => {
    this.setState({
        message: e.target.value
    });
}

handleClick = () => {
    alert(this.state.message);
    this.setState({
        message: ''
    });
}
  • input 여러개 다루기
    메서드 여러개 만들수 있지만 event 객체 사용하면 더 쉽게 처리 가능
    ㄴ onChange이벤트 핸들러에서 e.target.name은 해당 인풋의 name 가리킴. 즉 message
    이 값 사용해 state 설정하면 쉽게 해결
import React, { Component } from 'react';

class EventPractice extends Component {

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

handleChange = (e) => {
    this.setState({ // 객체 안에서 key를 []로 감싸면 
    // 그 안에 넣은 레퍼런스가 가리키는 실제 값이 key값으로 사용됨
      [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;
  • onKeyPress 이벤트 핸들링
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} // 이 인풋의 입력값은 usernname
                onChange = {this.handleChange} />

                <input type = 'text'
                name = 'message'
                placeholder = 'enter anything'
                value = {this.state.message} // 이 인풋의 입력값은 message
                onChange = {this.handleChange}
                onKeyPress = {this.handleKeyPress} />

                <button onClick = {this.handleClick}>확인</button>
            </div>
        )
    }
}
  • 함수형 컴포넌트로 구현
    위의 작업은 클래스형 컴포넌트로 구현한 것
const EventPractice = () => {
    // 두번째 원소는 첫번째 원소값 바꾸는 함수
    const [username, setUsername] = useState('');
    const [message, setMessage] = useState('');
    
    // e.target.name 활용하지 않고 onCHange련 함수 두 개 따로 만듬
    // but 인풋 개수 많다면 e.target.name 활용하는것이 좋다
    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 = 'enter name'
            value = {username}
            onChange = {onChangeUsername} />

            <input type = 'text'
            name = 'message'
            placeholder = 'enter anything'
            value = {message}
            onChange = {onChangeMessage}
            onKeyPress = {onKeyPress} />

            <button onClick = {onClick}>확인</button>
        </div>
    )
}

export default EventPractice

useState 통해 사용하는 상태에 문자열 아닌 객체 넣기

// useState 통해 사용하는 상태에 문자열 아는 객체 넣기
const EventPractice = () => {
    const [form, setForm] = useState({
        username : '',
        message: ''
    });

    // e.target.name값 활용하려면 useState쓸 때 인풋값들이 들어있는 form 객체 사용하면 됨
    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 = "enter anything"
            value = {message}
            onChange = {onChange}
            onKeyPress = {onKeyPress} />

            <button onClick = {onClick}>확인</button>
        </div>
    )
}
  • 정리
    리액트에서 이벤트 다루는 것은 순수 js나 jQuery등 사용한 웹에서 이벤트 다루느것과 비슷
    클래스형에서 할 수 있는 대부분의 작업은 함수형에서도 가능
    함수형에서 여러개의 인풋 관리 위해 useState에서 form 객체 사용
    이후에 useReducer와 커스텀 Hooks사용하면 이 작업 훨씬 쉬워짐

0개의 댓글