React/React 문법

[React]super()와 super(props)의 차이

DevStory 2021. 8. 5.

대부분 React 개발자들은 Class 컴포넌트를 구현할 때, constructor(props)에서 super(props)를 당연하게 사용했을 거라 생각합니다.

class App extends React.Component {
  constructor(props) {
    super(props);
    //...
  }
  //...
}

저 또한 super(props)를 당연하게 사용을 해왔기 때문에 아래 의문에 대해 답변을 할 수 없었습니다.

1. 생성자에서 super()를 호출하는 이유
2. super()에 props를 넘겨주는 이유

이번 포스팅에서는 super()와 super(props)의 차이에 대해 정리합니다.

StackOverFlow에서 아래 질문에 대해 영감을 얻었으며, Dan Abramov가 작성한 글을 일부 번역하여 작성하였습니다.

 

StackOverFlow에 올라온 질문 what's the differenece between "super()" and "super(props" in React when using es6 classes?

Dan Abramov의 Why Do We Write super(props)?


super()란?

JavaScript에서 super()는 Java에서 사용되고 있는 개념과 동일합니다.

자식 클래스가 생성될 때, 부모 클래스의 생성자를 참조합니다.

Class 컴포넌트에서 부모 클래스는 React.Component를 말합니다.

 

여기서 중요한 점은 JavaScript에서 super()를 선언 전까지 constructor() 안에 this 키워드를 사용할 수 없습니다.

※ constructror() 또는 super()에 props를 전달하지 않더라도 super() 선언 전에 this 키워드 사용 시 에러 발생합니다.

class App extends Component {
  constructor(props) {
    //아래 코드는 주석 해제하면 에러 발생함
    //console.log(this);
    super();
    console.log(this);
  }

  render() {
    return (
      <React.Fragment>
        <h1>HI</h1>
      </React.Fragment>
    );
  }

super() 선언 전에 this를 사용 가능하다고 가정해보자.

super() 선언 전에 this를 사용 가능하다고 가정하고 아래 코드가 어떻게 동작할지 예상해봅시다.

class ParentComponent extends Component {
  constructor(age) {
    this.age = age;
  }
}

class ChildComponent extends Component {
  constructor(age) {
    this.printAge();
    super(age);  
  }
  
  printAge() {
    console.log(`My Age is ${this.age}`);
  }
}

this.age가 초기화되기 전에 printAge() 함수에서 this.age가 호출되었습니다. JavaScript는 이렇게 애매한 경우를 허용하지 않기 위해 super() 호출 후 this를 사용할 수 있도록 강제적으로 제한하였습니다.


props는 왜 전달하는가?

props를 전달하는 이유는 props를 초기화하기 위한 과정이라고 예상할 수 있습니다.

class App extends React.Component {
  constructor(props) {
    super(props);
    //...
  }
  //...
}

그러나 React에서는 constructor()이 없어도 super()를 호출하지 않아도 this.props을 사용할 수 있습니다.

실제로 아래 코드는 constructor() 없이 정상적으로 동작합니다.

 

index.js

import { StrictMode } from "react";
import ReactDOM from "react-dom";

import App from "./App";

const rootElement = document.getElementById("root");
ReactDOM.render(
  <StrictMode>
    <App printString={"App"} />
  </StrictMode>,
  rootElement
);

App.js

render()에서 this.props.printString에 접근하였습니다.

console.log에 정상적으로 출력이 됩니다.

import React, { Component } from "react";

export default class App extends Component {
  render() {
    console.log(this.props.printString);
    return (
      <React.Fragment>
        <h1>HI</h1>
      </React.Fragment>
    );
  }
}

위 코드에서 this.props에 접근이 가능한 이유는 React는 생성자 호출 이후에 props 속성을 세팅해줍니다.

즉, React는 super의 인자로 props를 전달하는 것을 실수하더라도 정상적으로 동작되는 것을 보장해 줍니다.


왜 super(props)를 사용하는가?

위 코드를 통해 constructor()가 없어도 super()가 없어도 this.props에 접근할 수 있음을 확인하였습니다.

props를 초기화하지 않아도 this.props를 사용 가능한데, super(props)를 사용해야 하는 이유가 있을까?라는 고민에 직면하게 됩니다.

위 고민에 대한 답은 간단합니다.

생성자 내부에서 this.props를 사용하기 위해서입니다.

class App extends Component {
  constructor(props) {
    super(props);
    console.log(this.props.printString);
  }

  render() {
    return (
      <React.Fragment>
        <h1>HI</h1>
      </React.Fragment>
    );
  }
}

마무리

class fileds proposal를 사용하거나 또는 Hooks을 사용한다면 몰라도 되는 내용이지만, 아직까지 Class로 구현된 컴포넌트가 많기 때문에 알아두면 도움이 될 것 같습니다.

반응형

댓글