안녕하세요, 처음코딩입니다.
저는 개발 공부를 할 때, 코드 한 줄 씩 "왜"라는 질문을 던져가며 이해하려고 노력하는 편입니다.
리액트의 클래스형 컴포넌트를 공부할 때는 class를 선언하고 바로 뒤에 있는 constructor 함수와 그 안의 super 키워드가 필요하다는 것은, 자바스크립트 기초를 배울 때 접했던 개념이라 어느정도 이해는 되었지만 아직 완전한 제 지식이 된 느낌은 아니였습니다.
그래서 무의식적으로 사용해왔던 constuctor 함수와 super 키워드를 사용해야하는 이유는 무엇일까?
더 나아가 왜 인자로 props를 받아 super(props)를 사용하는지 고민해보는 시간을 가져보겠습니다.
겪었던 문제 :
리액트에서 super(props)를 사용하는 이유는 무엇일까?
해결하기 위해 시도했던 방법 :
1. contructor 함수와 super 키워드에 대해 다시 한 번 개념을 정리하였습니다.
contructor 함수는 객체를 생성하고 초기화하기 위한 생성자 함수이고,
super 키워드는 '.'과 '()'를 뒤에 붙여 사용하는 두 가지 용법이 있는데, 저희가 사용하는 '()'용법은 부모 클래스의 생성자 함수를 호출하는 함수라고 정리했습니다.
리액트에서는 constructor가 컴포넌트의 생성자 메서드가 되고, React.Component를 상속받기 위해 super(props)를 호출해주는 점까지 정리하였습니다.
2. 리액트를 내려두고 자바스크립트로만 부모와 자식 클래스를 만들어 상속을 구현해보았습니다.
부모 클래스인 Person에서 평균을 구하는 avg함수를 추가하기 위해, 부모 클래스의 코드를 전부 복사하여 자식 클래스에 붙여넣기 하였습니다
코드를 실행한 결과 다음과 같은 에러가 발생하였고 다음과 같은 정보를 알게 되었습니다.
"'this'에 접근하거나, 자식 클래스의 constructor함수를 리턴하기 전에 반드시 자식 클래스에서 super키워드를 호출해야한다."
즉, 상속받는 자식 클래스에서 constructor함수를 사용하기 위해서 super키워드가 필요하고,
그 안에서 this 키워드를 사용하려면 this 앞에 super를 호출해야한다라고 정리할 수 있었습니다.
그래서 다음과 같이 super()를 추가하여 에러를 해결하였습니다.
그렇다면 왜 자바스크립트는 생성자 함수 안에서 super 를 호출하기 전에는 this를 사용할 수 없는지 궁금했습니다.
3.자바스크립트에서 super 를 호출하기 전에는 this 를 사용할 수 없는 이유에 대해 찾아보았습니다.
저는 Dan Abramov의 Why Do We Write super(props)? 글을 보고 나서 이해할 수 있게 되었습니다.
아래의 코드로 예시를 들어보겠습니다.
만약 17번 라인처럼 super() 호출 전 this.avg()가 호출되었다면 avg 함수 리턴문 안의 this.first의 값은 아직 초기화 되지 않았음에도 함수가 실행되었습니다.
이런 상황들을 방지하고자 자바스크립트에서 이유있는 언어적 제약을 걸어둔 것이라고 생각합니다.
그렇다면 super 를 반드시 호출해야 하는 이유는 설명이 되었지만 아직 해결되지 않은 질문이 하나 남았습니다.
리액트에서는 왜 props 를 인자로 전달해야 할까요?
4. 리액트에서 왜 super()에 props를 인자로 전달하는지 찾아보았습니다.
제가 찾은 결론부터 말씀드리면, 첫 번째로는 React.Component 객체가 생성될 때 props 속성을 초기화하기 위해 부모 컴포넌트에게 props 를 전달하기 때문입니다.
이에 대한 근거는 리액트 소스코드에서 확인할 수 있습니다.
하지만 첫 번째 근거로는 제가 이해하기에는 부족했습니다.
왜냐하면 props 전달 없이 super() 를 호출하더라도 render 함수 및 기타 메소드에서 여전히 this.props 를 사용할 수 있었기 때문입니다.
그 이유를 찾아보니 리액트가 제가 작성한 컴포넌트의 생성자 호출 이후, 해당 객체에 props 속성을 세팅을 해준다고 합니다.
지금처럼 이해가 부족한 상태에서 super에 props를 전달하고 싶지 않으니 super()만 사용해도 되나 생각하기도 했습니다.
결국 super(props)를 사용해야하는 의문을 풀 수 있었는데, 그 이유는 생성자 내부에서 super() 가 호출되고 생성자가 끝나기 전까지 this.props 는 undefined 가 되기 때문입니다.
this.props가 undefined 인 생성자 내부에서 다른 함수를 또 호출하는 경우에,
이로 인해 발생하는 문제들을 디버깅 해야 할 경우가 생길 수 있습니다.
super()만 사용한다면 결국 곤란한 상황을 마주하게 될 것을 알게 되었고, super(props) 를 꼭 호출해야만 하는 이유에 대해 이해할 수 있게 되었습니다.
사실 클래스 필드 문법을 사용하게 되면 constructor 함수와 super키워드를 생략해도 되니 이에 대한 고민을 하지 않아도 될 수 있습니다.
하지만 아예 모른채 편한 문법을 사용하는 것과, 이전의 문법을 이해한 채로 새로운 문법을 받아들이는 것은 큰 차이가 있다고 생각합니다.
왜냐하면 기존의 문법보다 더 간략해진 코드를 보아도 숨겨진 원리를 이해할 수 있으며, 지금 내가 사용하는 문법의 필요성 또한 느낄 수 있기 때문입니다.
노력없이 쉽게 얻은 결과는 큰 만족감을 줄 수 없으며, 쉽게 사라지는 것처럼 그저 처음부터 쉬운 문법만 편식한다면 아마 중요한 순간 휘청거리게 될 때가 올 수도 있다고 생각합니다.
그렇기 때문에 한 번쯤은 클래스 필드 문법을 사용하기 전 constructor 함수와 super 키워드 그리고 더 나아가 super(props)까지 고민해보는 시간을 갖으면 좋겠다는 생각으로 이만 마치겠습니다.
긴 글 읽어주셔서 감사합니다.
과정에서 느낀 점 :
그리고 생활코딩에서 class 문법과 상속에 대하여 3달 전부터 몇 번을 듣고 사용도 해왔지만, 오늘에서야 이고잉님께서 하시는 말씀이 이해가 되었습니다.
이런 개념이 있다라고 받아들이며 사용했던 때와 달리, "왜" 라는 물음을 하나 던졌을 뿐인데 정말 필요한 개념이구나.. 내가 이러한 이유로 사용해왔구나를 알게되어서 너무 기뻤습니다.
같은 영상에서 매 번 다른 느낌을 받을 수 있다는 것도 놀랐으며, 그 느낌은 어제의 제 자신보다 오늘 성장했다는 증거이기도 하여 행복감도 느껴졌습니다.
저는 "왜"라는 물음을 던지는 것을 좋아하는 학생이라 진도면에서는 학습 속도가 느린 편이였는데, 어느 정도 이해하고 한 바퀴를 돌고 다시 돌아와 "왜"를 던졌을 때 더 효율적일 수 있다는 것을 느꼈습니다.
이해가 가지 않는다고 하나만 붙잡고 있기 보다, 새로 배운 개념들이 머릿속에서 무르익을 수 있는 시간을 존중해주며 다른 곳도 둘러보고 돌아오는게 저한테 좋은 공부 방법일 수 있겠구나를 깨달은 뜻 깊은 날입니다.
Reference
Dan Abramo - Why Do We Write super(props)?
overreacted.io/why-do-we-write-super-props/
stackoverflow -How to extend a class without having to use super in ES6?
stackoverflow.com/questions/31067368/how-to-extend-a-class-without-having-to-use-super-in-es6
gtihub - facebook/react
github.com/facebook/react/blob/1d25aa5787d4e19704c049c3cfa985d3b5190e0d/packages/react/src/ReactBaseClasses.js#L22
'개념 정리 > React' 카테고리의 다른 글
리액트에서 Ajax 요청하기 (왜 Ajax요청을 "componentDidMount"에서 해야할까?) (0) | 2020.11.27 |
---|---|
리액트에서 key 설정 (왜 map 함수에 전달되는 콜백 함수의 인수인 "index"값을 사용하면 안되는가?) (2) | 2020.11.26 |
리액트 props.children (0) | 2020.11.08 |
댓글