본문 바로가기
Archive

React 합성 이벤트 & Class Component의 this & 함수 바인딩

by livemehere 2022. 6. 6.

Dom Element 에서 이벤트는 합성 이벤트 이다.

  • form 의 경우 preventDefault() 를 명시적으로 호출 해야한다
  • 브라우저 고유의 event 와 정확히 동일하게 동작하지는 않는다. 하지만 이가 브라우저의 호환성을 맞춰준다.

Class Component 를 사용할 때의 this

  • 일반적인 이벤트 핸들링 패턴은, 핸들러를 메서드로 만드는 것이다. 하지만 이때 javascript 의 바인딩 문제를 해결 해 주어야한다.
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      a: 0
    };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    console.log(this.state.a);
  }

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

export default App;
  • 위와 같이 onClick 이벤트에 바로 함수를 넣으면, 메서드를 참조하게 된다. 이때 생성자 함수에서 처럼 함수를 바인딩 해주지 않으면 참조하는 값이 undefined 가 된다.

왜 이럴까? javascript 의 동작방식에 그 해답이 있다. javascript 에서 this는 반드시 실행시점에 결정된다는 점을 유의해야한다. 그렇다면 render()함수가 호출되고 나서, DOM 에서 this.handleClick 은 window 객체를 참조하게 된다(실행 context가 window가 됨)

  • 이를 해결하기 위해서는 위 코드와 같이 직접 bind() 함수를 선언하는 방법 or arrow function 을 사용해서 자동으로 바인딩 시키는 방법이 있다(class field 문법). 혹은 콜백 자체에 arrow function을 사용하는 방법이 있습니다.

arrow function 은 항상 상위 스코프의 this 를 바인딩하는데, 이를 Lexical this 라 합니다.

React에서 지원하는 class field 문법 을 사용한 예시 (arrow function)

Class Field 문법이란 ? 말그대로 class 에 사용되는 새로운 문법입니다. React Component 를 만들때 반드시 constructor()에 super() 와 state를 정의해주고, 모든 메서드들을 바인딩 해주었습니다. 이 동작들을 간소화할 수 있게 해주는 문법으로써, 핵심적으로 constructor() 를 정의하지 않습니다. 모든 메서들은 arrow function 으로 정의하고, 이는 자동으로 바인딩됩니다.

constructor(), this 가 사라진 형태

class App extends React.Component {

    state = {
        a:10,
        name:'kong'
    }

  handleClick = () => {
    console.log(this);
  };

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

export default App;

callback 에 arrow function 사용 예시 (권장되지 않음 : 콜백 성능 이슈)

이 방식의 문제점은 App 컴포넌트가 재렌더링 될때마다 새로운 callback을 생성한다는 점입니다. 대부분의 경우에 문제가 없지만 만약 이 콜백함수가 자식 컴포넌트의 props로 전달되고있다면, 콜백이 생성될 때마다 자식 컴포넌트도 재렌더링 됩니다. 이러한 문제 때문에 class field 문법을 사용하거나, 생성자 안에서 바인딩 해주는 방식이 권장됩니다.

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      a: 0
    };
  }

  handleClick() {
    console.log(this);
  }

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

export default App;

callback에서 binding 하기

class App extends React.Component {

  constructor(props){
    super(props);
  }

  handleClick(pram){
    console.log(this,pram);
  };

  render() {
    return (
      <div>
        <h1>App</h1>
        <button onClick={this.handleClick.bind(this,3)}>Click</button>
      </div>
    );
  }
}

export default App;
반응형

'Archive' 카테고리의 다른 글

React Custom Hook return Array vs Object 차이  (0) 2022.06.07
React 조건부 렌더링(falsy에서 유의하자)  (0) 2022.06.06
AWS serverless (API gateway + lambda)  (0) 2022.06.04
AWS EB 사용하기  (0) 2022.06.03
React Query 도입하기  (0) 2022.05.19