본문 바로가기
React

React this.state의 this의 의미

by ttum 2020. 4. 6.

React에서 코드를 작성하다가 한번쯤 마주하게 되는 에러가 있다.

📌문제가 발생한 상황

컴포넌트들의 구조는 아래 그림과 같이 생겼다. App 컴포넌트는 fruitList와 searchFruit이라는 두개의 state를 가지고 있고, Search 컴포넌트에서 검색 내용의 input(검색내용)을 받으면 App 컴포넌트의 searchFruit만 변경해주면 되는 상황이다.

- App 컴포넌트의 onSearchChange() 함수

  onSearchChange(event) {
    this.setState({ fruitSearch: event.target.value });
  }

- Search 컴포넌트에서 onSearchChage를 호출하는 부분

const Search = ({ onSearchChange }) => {
  return (
    <div className="pa2">
      <input type="search" onChange={onSearchChange} />
    </div>
  );
};

 

App 컴포넌트의 onSearchChange의 this가 문제가 되어 에러가 발생했다.

이 상황에서 onSearchChange의 this는 Search 컴포넌트 input태그의 onChange에서 호출했다.

(주체는 window객체이겠지만 use strict 모드에서 보안을 위해 this는 undefined가 된다.)

어쨌든 중요한 것은 onSearchChange함수에서 this는 App 컴포넌트가 아니라는 점이다.

따라서 this.setState를 인식하지 못하는 것이다.

🔨해결책은 무엇인가?

Arrow function을 사용하면 된다. 따라서 아래와 같이 함수를 수정하면 해결이 된다.

  onSearchChange = (e) => {
    this.setState({ fruitSearch: e.target.value });
  };

Arrow function의 this는 항상 그것을 둘러싼 enclosing scope에서 상속받는다.(참고자료) 결론만 말하면 Arrow function을 사용하면 되는 것이지만 더 제대로 이해하기 위해서는 자바스크립트의 스코프 규칙에 대해 알아야 한다.

스코프는 일반적으로 lexical scope와 dynamic scope가 있다. 두개의 차이점을 알아보자.

1. Lexical scope

자바스크립트는 기본적으로 lexical scope를 따른다. lexical scope는 함수가 정의된 곳에서 사용하능한 변수들이 정의된다. 함수가 정의된 곳을 둘러싼 부모 영역에 따라 변수가 결정된다. 예시를 보면 쉽게 이해할 수 있다.

function a() {
  console.log(fruit);
}

function b() {
  var fruit = "apple";
  a();
}

var fruit = "banana";
b();

 위 코드를 실행하면 "banana"가 출력으로 나온다. a 함수에서 fruit이 없으니 scope chain을 따라 그것을 둘러싼 부모 영역에 가서 fruit(banana)을 가져온 것이다. (여기에서는 부모영역이 전역이다.)

2. Dynamic scope

Dynamic scope는 함수가 어디에서 호출되었는가?에 따라 변수가 결정이 된다. 위의 예시를 다시 보자면 함수 a는 함수 b 안에서 호출되었다. 그렇기 때문에 dynamic scope에 따르면 위 코드의 결과는 "apple"이 나온다.

 

자바스크립트는 일반적으로 lexical scope를 따르지만 this에 대해서는 dynamic scope의 규칙이 적용된다. 

다시 문제의 본론으로 돌아가서보자. 이 글의 주된 문제였던 setState 앞의 this가 코드를 읽기에는 이를 둘러싼 App 컴포넌트가 되어야할 것 같았지만 그것을 호출한 주체는 따로 있었기에 this는 다른 것이 되었다.

따라서 this.setState는 호출될 수 없었다.

🤔그렇다면 왜 Arrow function이 해결해줄까?

위에서도 말했지만 Arrow function의 this는 항상 그것을 둘러싼 enclosing scope에서 상속받는다. 다시말해 Arrow function에 대해서는 this에 lexical scope이 적용되는 것이다.

따라서 함수 선언문이 아닌 화살표 함수(Arrow function)로 표현했을 때에 문제가 해결된 것이다.