본문 바로가기
WEB/기초

[Web] React lifecycle method,props, super(props) vs super()

by IT황구 2021. 7. 10.
728x90
반응형

반갑습니다. 슬슬 길게쓰기 힘들어지네요..

지난번에 만든 MyComponent를 약간 수정해보겠습니다.

원하는 결과물 :

1번을 클릭하면 2번처럼 새로운 설명이 나오게 해보겠습니다.

일단 위의 결과물을 만들기에 앞서, React의 component life cycle method에 대해서 알아보겠습니다.

이걸 왜 알아야 하냐구요? 원하는 순서대로 실행을 하기 위해서는 필수랍니다. 물론 이 life cycle은 class style react에서만 유효합니다.

function style은 hook을 이용한답니다.

리액트 어플리케이션에서는

컴포넌트가 만들어지고 DOM에 삽입될 때 다음과 같은 method들이 호출됩니다.

1. constructor()

2. getDerivedStateFromProps() (잘 사용되진 않습니다)

3. render()

4. componentDidMount()

과연 진짜인가 확인해봅시다.

import { React, Component } from "react";
import {
  Card,
  CardImg,
  CardBody,
  CardTitle,
  CardText,
  CardImgOverlay,
  CardSubtitle,
} from "reactstrap";

export class Mycomponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      dishes: null,
    };
    console.log("constructor called");
  }

  componentDidMount() {
    console.log("componentDidMount called");
  }

  render() {
    console.log("Component Rendered");
    return (
      //container는 bootstrap grid모양이 필요할때 하는것이다
      //https://getbootstrap.com/docs/5.0/layout/containers/#how-they-work
      <div className="container">
   
      </div>
    );
  }
}

f12를 눌러 콘솔창을 확인해 보시면, 이렇게 constructor, render , didmount 순서로 불리게 됩니다.

반드시 constructor을 만들어야 하는것은 아닙니다. 아래와 같이 state를 지정하거나, event handler method를 instance로 binding 할때 사용합니다.

super(props)는 뭘까요? 이건 Component를 상속받는 subclass에는 반드시 붙여줘야 합니다.

이걸 사용하지 않으면 this.props가 undefined가 나오게 됩니다. 한번 직접 확인해봅시다.

이런식으로 3이 나오게 됩니다. ( 순서는 Constructor에서 이미 초기화가 가장 먼저 됐으니까, 다음에 불린 render()에는 3이 들어가 있습니다)

한번 super를 지워볼까요?

super()를 사용하지 않으면 this가 사용되지 않는답니다. 오류가 나버립니다.

you should call super(props) before any other statement. Otherwise, this.props will be undefined in the constructor, which can lead to bugs. (React Docs)

React Docs에도 super(props)를 불러야 한다고 나와있습니다.

저는 꼭 super(props)만 해야하나 싶습니다. super()은 안되나요?

결론은 안됩니다. 쓰지 않으면 this.props를 사용할 수 없습니다. 굉장히 당연한 이야기인데, 직접 눈으로 보기 전까지 믿지 않았습니다.

1. super(props)

App.js에서 props로 javascript object를 보내보겠습니다

props를 선언후 받아보겠습니다.

굉장히 잘 받아왔습니다.

이번엔 props를 제거해보겠습니다.

2. super()

undefined가 나오게 됩니다.

결론 :

constructor(props) 아래에는 반드시 super(props)를 써줘야 한다.

Docs에서 꼭 하라고 하면 이유가 있답니다!!

=> props로 접근하는것은 Constructor 내부에서만 해당됩니다.

Constructor 외부에서 this.props.dish 로 접근하는건 가능합니다. Constructor 내부에서 this.props로 접근하기 위해서 super(props)를 하는것 입니다.

 

설명은 끝났고,

이제 화면을 만들어봅시다.

food.js에 json형태의 파일을 만들어서 export 시킵니다.

App.js 에서는 this.state에 저 dish를 넣어줍니다. (외부 파일에서 값을 불러옵니다)

import { React, Component } from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import { Navbar, NavbarBrand } from "reactstrap";
import { Mycomponent } from "./components/MyComponent";
import { dish } from "./shared/food";
//import "./App.css";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      food: dish,
    };
  }

  render() {
    return (
      <div className="App">
        <Navbar dark color="primary">
          <div className="container">
            <NavbarBrand href="https://www.naver.com">My Naver</NavbarBrand>
          </div>
        </Navbar>
        <Mycomponent param={this.state.food} />
      </div>
    );
  }
}

그다음 user-defined component에 state를 param으로 담아서 보냅니다.

그러면 Mycomponent에서는 props를 통해서 사용 할 수 있습니다. (다른 파일로 값을 전달한것)

import { React, Component } from "react";
import {
  Card,
  CardImg,
  CardBody,
  CardTitle,
  CardText,
  CardImgOverlay,
  CardSubtitle,
} from "reactstrap";

export class Mycomponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      dishes: null,
      num : 3,
    };
    console.log(this.props);
    console.log("constructor called");
  }

  componentDidMount() {
    console.log("componentDidMount called");
  }

  onDishSelect(dish) {
    this.setState({
      dishes: dish,
    });
  }
  // this.setState({});
  // this.setState = ({}); 로 해서 안됐음. 에러라고 안알려줌 ㅡㅡ

  onRender(dish) {
    if (dish != null) {
      return (
        <Card className="col-12 col-md-6 col-lg-4">
          <CardImg src={dish.image} alt={dish.name} />
          <CardImgOverlay>
            <CardTitle>{dish.name}</CardTitle>
            <CardBody>
              <CardText>{dish.description}</CardText>
            </CardBody>
          </CardImgOverlay>
        </Card>
      );
    } else {
      return <div>gg</div>;
    }
  }

  render() {
    const myname = this.props.param.map((dish) => {
      return (
        //<Col xs="12" md="4" xl="4" className="mb-3 mt-3" key={dish.id}>
        <div key={dish.id} className="mb-3 mt-3 col-12 col-md-6 col-lg-4">
          <Card
            onClick={() => {
              this.onDishSelect(dish);
              console.log("clicked2");
            }}
          >
            <CardImg width="100%" src={dish.image} alt={dish.name}></CardImg>

            <CardImgOverlay>
              <CardTitle>{dish.name}</CardTitle>
              <CardSubtitle className="text-center">
                {dish.category}
              </CardSubtitle>
              <CardBody>
                <CardText>{dish.description}</CardText>
              </CardBody>
            </CardImgOverlay>
          </Card>
        </div>
      );
    });
    console.log("Component Rendered");
    return (
      //container는 bootstrap grid모양이 필요할때 하는것이다
      //https://getbootstrap.com/docs/5.0/layout/containers/#how-they-work
      <div className="container">
        <div className="row">{myname}</div>
        <div className="row">{this.onRender(this.state.dishes)}</div>
        <div className="row">{this.state.num} </div>
      </div>
    );
  }
}

천천히 코드의 순서를 따라가봅시다.

1. constructor(props)가 먼저 실행된다.

this.state.dishes에는 null값을 초기값으로 줬습니다.

2. render()이 실행된다.

jsx를 통해서 엘리먼트를 변수 myname에 담습니다. (jsx는 html보다는 javascript에 가까우므로 camelcase로 지어야합니다)

사실 myName으로 해야합니다. (죄송합니다..)

그다음 javascript expression으로 div안에 넣어서 view로 보여줍니다.

this.props.params.map((dish)=>{} 을 봅시다.

이전에 있던 App.js의 dish의 배열을 순회하면서, 새로운 배열을 반환하는 함수입니다.

props로 접근했단것을 봐야합니다.

그 이후 return()에서

myname에 해당하는 변수가 들어가서 view를 구성합니다

그 다음은 this.onRender 메소드인데 onRender()을 보면 dishes는 아직 null이므로 gg 만 반환합니다..

이제 onClick의 경우를 생각해봅시다.

어떤 카드를 클릭한 경우 this.setState({})에서 dishes의 상태를 변화시키빈다.

setState는 React에게 업데이트 된 상태를 다시 렌더링(새로고침) 하라고 합니다. 이벤트 핸들러나, 서버의 응답에 반응할 때 사용된다. 따라서 dishes의 state가 바뀌고 다시 rendering이 됩니다.

이렇게 클릭이 된 후에 render가 다시 된 것을 확인할 수 있습니다.

이때 최초에 만들어진 constructor와, DidMount는 호출되지 않은것을볼 수 있습니다.

다시 렌더링이 되면서, this.onReder()에서는 dishes가 click 된 dish의 값으로 변해있을 것입니다.

null이 아니므로, Card들이 리턴됩니다!! (아래에 카드로 dish의 값에 대한 설명이 들어간다)

이렇게 클릭한것에 대한 정보들이 담겨서 <div>로 감싸져서 나오게 됩니다.

마지막으로 reactstrap에 관한 설명 조금만 하고 마무리 하겠습니다.

1. <div className="container"> 으로 하면 bootstrap의 container모양 (그리드 모양) 으로 자동으로 스타일을 맞춰줍니다.

또한 reactStrap의 Row Component 대신에, <div className="row"> "col" 이런식으로 Row와 Col 컴포넌트를 대신할 수 있습니다.

https://getbootstrap.com/docs/5.0/layout/containers/#how-they-work

 

Containers

Containers are a fundamental building block of Bootstrap that contain, pad, and align your content within a given device or viewport.

getbootstrap.com

 

2. col-md-12, col-lg-3

이런게 뭔 뜻일까요?

responsive web design을 할때 화면의 사이즈마다 나오는 컬럼의 수를 변경시킵니다.

기본은 xs이고, sm, md, lg, xl 스몰,미디움,라지,엑스라지가 있습니다.

12의 뜻은 뭘까요?

column의 개수가 1개라는 뜻입니다.

화면의 width를 12등분하여 1개의 컴포넌트당 12개의 칸을 차지하라는 뜻입니다.

즉 col-lg-3은 large size의 화면에서 한개의 컴포넌트당 3개의 칸을 차지하라는 뜻입니다.

이 말은 1개의 row당 4개의 Component가 들어간다고 생각하면 됩니다.

https://www.geeksforgeeks.org/meaning-of-numbers-in-col-md-4-col-xs-1-col-lg-2-in-bootstrap/

 

Meaning of numbers in “col-md-4”,“ col-xs-1”, “col-lg-2” in Bootstrap - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

저 링크를 보시면 완전히 이해가 될 것입니다.

https://getbootstrap.com/docs/4.4/layout/grid/#grid-options

 

Grid system

Use our powerful mobile-first flexbox grid to build layouts of all shapes and sizes thanks to a twelve column system, five default responsive tiers, Sass variables and mixins, and dozens of predefined classes.

getbootstrap.com

 

이 Grid system을 보면 어떤 사이즈를 기준으로 나누는지 알 수 있습니다. 저도 나중에 만들때 저 사이즈표를 참고해야 겠네요..

오늘은 여기까지...

끝.-

728x90
반응형