본문 바로가기
programming_kr/react

이벤트 제어

by JSsunday 2021. 1. 19.
728x90

 

React 요소의 이벤트 제어의 특징은 아래와 같습니다.

 

  • React 이벤트는 소문자 대신 camelCase를 사용합니다.
  • JSX에 문자열 대신 함수를 전달합니다.
function activateLaser(){...};
//HTML
<button onclick="activateLasers()">
  Activate Lasers
</button>

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

 

다른 차이점으로는 React에서 기본 동작을 막기 위해 false 리턴을 사용할 수 없다는 것입니다. 반드시 명시적으로 preventDefault 를 호출해야 합니다. 예를 들어 HTML에서 새로운 페이지를 여는 기본 링크 동작을 막으려면 이렇게 작성할 수 있습니다.

 

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

 

React에서는 이렇게 작성합니다.

 

function ActionLink() {
  function handleClick(e) {
    e.preventDefault(); //명시적으로 호출.
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>{/*함수 전달*/}
      Click me
    </a>
  );
}

 

React를 사용할 때 일반적으로 DOM 요소가 생성된 후에 리스너를 추가하기 위해 addEventListener를 호출할 필요가 없습니다. 대신 요소가 처음 렌더링될 때 리스너를 제공합니다.

 

ES6 class를 이용해 요소를 정의할 때 이벤트 핸들러의 일반적인 패턴은 클래스의 메서드 형태입니다. 예를 들어, 아래 Toggle 컴포넌트는 “ON” 과 “OFF” state를 유저가 토글할 수 있게 하는 버튼을 렌더링합니다.

 

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(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

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

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

 

JSX 콜백에서 this의 의미에 대해 주의해야합니다. 자바스크립트에서 클래스 메서드는 기본적으로 bind되지 않습니다. 만약 this.handleClick 바인드를 잊은채로 onClick 에 전달하면, this는 함수가 실제로 호출될 때 undefined로 취급됩니다.

이건 React에서 정의한 동작이 아닙니다. 자바스크립트의 함수의 동작 방식의 일부입니다. 일반적으로 onClick={this.handleClick}처럼 ()없이 메서드를 참조하면, 그 메서드를 bind 해야합니다.

만약 bind 를 호출하는 게 귀찮은 경우 이 문제를 해결할 수 있는 두가지 방법이 있습니다. 만약 실험 기능인 퍼블릭 클래스 필드 문법을 사용한다면 클래스 필드를 정확히 콜백에 bind할 수 있습니다.

 

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>
    );
  }
}

 

다른 방법은 arrow function을 사용할 수도 있습니다.

 

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>
    );
  }
}

 

이 문법의 문제점은 LogginButton을 렌더링할 때마다 서로 다른 콜백이 만들어지는 것입니다. 대부분의 경우에서 크게 문제는 없습니다. 하지만 만약 콜백에서 하위 컴포넌트에 prop을 전달하는 경우, 이 컴포넌트는 큰 비용으로 다시 렌더링될 수 있습니다. 이런 종류의 성능 문제를 피하기 위해 보통 생성자 함수에서 바인딩하거나 클래스 필드 문법을 사용하는 걸 권장합니다.

 

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

 

위 두 라인은 동일하며, arrow functions Function.prototype.bind를 각각 사용하고 있습니다.

두 경우 모두, React 이벤트를 나타내는 e 파라미터는 ID 뒤에 두 번째 인수로 전달됩니다. arrow function을 사용하여 명시적으로 전달해야하지만, bind를 사용하면 추가 인수가 자동으로 전달됩니다.

 

이벤트 제어하기
728x90

'programming_kr > react' 카테고리의 다른 글

리스트와 키  (0) 2021.01.24
조건부 렌더링  (0) 2021.01.21
state와 lifecycle  (0) 2021.01.16
컴포넌트와 props  (0) 2021.01.13
요소의 렌더링  (0) 2021.01.10

댓글