본문 바로가기

개념/React

[React] onClick 이벤트가 렌더링할 때 자동 호출 되는 문제

💥문제발생

onClick 이벤트로 함수를 전달하고자 하는데, 아래와 같은 식으로 작성하니 화면이 처음 랜더링 할때 함수가 실행되는 현상이 발생하였다. (함수는 writeConsole이라고 간단하게 콘솔창에 메세지만 띄우는 함수로 대체한다.)

import React, { Component } from "react"

class Message extends Component {
  writeConsole = string => {console.log(string)}
    
  render() {
    return (<button onClick={this.writeConsole('아무말')}>버튼</button>)
  }
}

export default Message

이렇게하고 보니 처음 화면이 render할때만 함수가 실행되면서 콘솔창에 메세지가 뜨는 것이 아닌가. 그리고 버튼을 누르면 제대로onClick 함수가 자동하지 않았다. (onclick도 아니고 onClick이라고 제대로 썼는데)


💩원인

문제1. 렌더할떄 onClick 콜백이 자동 호출됨

문제2. 클릭을 하면 onClick 콜백이 호출되지 않음

구글링을 통해서 알아내보니, 문제 두가지 각각 다른 두가지 원인이 있었다. 

 

(문제1) 일단 렌더링 될때 onClick이 자동 호출되는 원인은 onClick에 콜백을 걸어주는 방식이 잘못됐기때문이다. onClick에 함수의 호출 writeConsole()을 넣지 말고 함수 자체 writeConsole를 넣어야하한다. 그냥 호출하는 방식으로 콜백을 지정하면 render하는 과정에서 호출문을 읽고 실행시켜버린다고 한다. 그럼 이건 오케이!

 

(문제2)근데 왜 클릭을 하면 onClick의 콜백을 호출하지 않을까?

자바스크립트에서 onClick 콜백을 호출할때 this가 정의되지 않는다는 문제가 있었다.

onClick이 발생하는 순간 this.writeConsole('아무말')을 실행해야 하는데 이때 자바스크립트 엔진은 this가 무엇인지 몰라서 마냥 타고 올라가기 때문에, this가 window나 undefined가 된다고 한다.

 

그러니까 요약하자면, onClick이 발생할때 자바스크립트는 클래스 문법을 고려하지 않고 그냥 무조건 콜백을 실행한다는것! 그럼 당연히 this가 뭔지 모르지. 이렇게 함수의 scope가 정해지는 것을 동적스코프(dynamic scope)라고 한다.


🔑해결01

구글링을 해본 결과 두가지 해결법이 있었는데 하나는 화살표 익명함수로 콜백을 감싸주는 것이다.

<button onClick={() => {this.writeConsole('아무말')}}>버튼</button>

//혹은 아래와 같이 중괄호를 생략할 수도 있다.

<button onClick={() => this.writeConsole('아무말')}>버튼</button>

 

왜 화살표 함수(arrow function)를 사용하면 해결이 될까??

 

함수를 호출하는 곳 기준으로 상위 스코프를 결정하는(동적 스코프) 보통의 자바스크립트 함수와 다르게,

arrow function은 함수를 선언한 곳을 기준으로 상위 스코프를 결정한다고 한다

다시말해 화살표 함수를 사용하면 함수를 선언한 곳에서 this를 참조한다는 뜻!!

 

이걸 바로 렉시컬 스코프(Lexical Scope, 정적범위) 라고한다.

이에 대해선 mdn의 글을 참조해봐도 좋다.

 

하지만 공식문서에 의하면 이 방법은 문제가 있는데, 바로 컴포넌트가 렌더링될 때마다 사실상 다른 콜백이 생성된다는 것이다!! 대부분의 경우 문제가 되지 않으나, 콜백이 또다시 하위 컴포넌트에 props로서 전달된다면 그 컴포넌트들은 추가로 다시 렌더링을 수행할 수도 있다고 한다. 이걸 우려해서 공홈에선 생성자 안에서 바인딩하는 아래의 두번째 방법을 권하고 있다.


🔑해결02

<button onClick={this.writeConsole.bind(this,'아무말')}>버튼</button>

위와 같이 bind문법을 사용해서 this를 연결해주면 문제 해결!


한마디

그냥 되는 방법만 마냥 받아들이지 않고,

안되는 방법에서 왜 안될까 고민하는 과정에서 정말 배우는 게 많은 것같다. 구웃