5.Handling Events

(React 공식문서의 main concepts 번역 글입니다.)

함께보면 이해가 쏙쏙 https://youtu.be/TCx_yNlxYNA

react element가 event를 다루는 것은
DOM element가 event를 다루는 것과 비슷하다.

event 사용에 대한 문법적 차이점(HTML과 JSX에서)

다만 syntactic한 차이점 2가지가 있다.

  • react에서 event는 camelCase로 이름 짓는다.
  • JSX를 사용하면 event handler로 function을 전달한다.(string 아님)

아래 예시로 HTML과 JSX에서의 차이를 알아보자.

첫번째, HTML에서 function을 전달할 때

<button onclick="activateLasers()">
  Activate Lasers
</button>

두번째, JSX에서 function을 전달할 때

<button onClick={activateLasers}>
  Activate Lasers
</button>

React의 JSX에서는 표현식으로 function을 전달한 것을 확인할 수 있다.

JSX에서 default behavior를 prevent하는 방법

JSX에서는 false를 return해서 default behavior를 막을 수 없다.

HTML에서는 아래와 같이 default behavior를 막을 수 있었다.

<a href="#" onclick="console.log('The link was clicked.'); return false">
  Click me
</a>

하지만 react의 JSX에서는 아래처럼 해야 막을 수 있다.

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

preventDefault()(하이라이팅된 부분)로 default behavior를 막을 수 있다.
또한 여기서 e는 event를 의미한다.(표준이기에 모든 브라우저에서 사용 가능)

JSX에서 event listener 추가하기

HTML에서는 event listener를 추가하기 위해
DOM element가 만들어진 후 addEventListener를 call 했다.

하지만 React의 JSX에서는
처음 React element가 render될 때 listener를 추가해주면 된다.

class component에서는 method로 event listener를 추가하면 된다.
아래 예시를 보자.

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback    this.handleClick = this.handleClick.bind(this);  }

  handleClick() {    this.setState(state => ({      isToggleOn: !state.isToggleOn    }));  }
  render() {
    return (
      <button onClick={this.handleClick}>        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

handleClick()이라는 method를 선언(두번째 하이라이팅된 부분)해서
Toggle component에 event listener를 추가했다.

그리고 constructor에서 bind(this) 해주고 있다.(첫번째 하이라이팅된 부분)
event listener가 callback으로 주어졌을 때
this값을 Toggle component로 bind하기 위해서이다.

만약 bind을 안해준다면
onClick에 할당된 callback은(세번째 하이라이팅된 부분) handleClick 내부에서 this값은 undefined이 된다.

javascript에서는 class method가 class에 bind되어있지 않기 때문이다.

constructor안에서 bind를 다시 해주지 않는 방법

2가지 방법이 있다. 먼저 class fields syntax를 활용하는 방법이다.
(표준문법은 아니므로 주의해서 사용하자)

class LoggingButton extends React.Component {
  // This syntax ensures `this` is bound within handleClick.  // Warning: this is *experimental* syntax.  handleClick = () => {    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

handleClick을 method로 선언할 때
arrow function으로 선언하게되면 this값이 bind된다.
(arrow function의 특성 활용)

두번째, arrow function을 callback에서 사용할 수도 있다.

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    // This syntax ensures `this` is bound within handleClick
    return (
      <button onClick={(e) => this.handleClick(e)}>
        Click me
      </button>
    );
  }
}

위처럼 callback에서 arrow function을 사용하면
LoggingButton을 render 할 때마다
새로운 callback(handleClick)이 만들어진다.

만약 이 callback(handleClick)이
자식 component에게 props를 넘겨준다면
자식 component들은 추가적으로 다시 rendering 될 것이다.

따라서 constructor binding이나 class fileds syntax를
사용하는 것을 권장한다.

event handler에게 arguments 전달하기

보통 반복문 안에서 id값을
추가 argument로 전달해야 하는 경우가 있다.

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

위 코드에서 첫번째, arrow function에서 id값을 줄 때
event를 e로 전달해주어야 한다.

하지만 두번째, bind를 사용하는 경우
event를 따로 전달하지 않아도 자동으로 전달된다.
(나중에 lists and keys 블로깅에서 이에 대해 자세히 다루겠다.)


[david hwang]
Written by@[david hwang]
깊게 이해하고 넓게 소통합니다.

GitHubMedium