Component, Life Cycle, JSX

younghyun·2022년 2월 20일
1

컴포넌트

재활용 가능한 UI 구성 단위

특징

재활용하여 사용할 수 있다.
코드 유지보수에 좋다.
해당 페이지가 어떻게 구성되어 있는지 한 눈에 파악하기 좋다.
컴포넌트는 또 다른 컴포넌트를 포함할 수 있다. (부모 컴포넌트 - 자식 컴포넌트)

종류

Class형 컴포넌트(Class Component)

선언 방식

import React, {Component} from 'react';

class App extends Component {
  render() {
    const name = 'react';
    return <div className="react">{name}</div>
  }
}

export default App;

특징

  • class 키워드 필요
  • Component로 상속 받아야 함
  • render()메소드 이용해서 JSX반환
  • state, lifeCycle 관련 기능사용 가능하다.
  • 메모리 자원을 함수형 컴포넌트보다 조금 더 사용한다.
  • 임의 메서드를 정의할 수 있다.

기능

  • constructor안에서 this.state 초기 값 설정 가능.
  • constructor없이 바로 state 초기값 설정할 수 있음.
  • 클래스형 컴포넌트 state는 객체 형식
  • this.setState 함수로 state값을 변경할 수 있다.
  • this.props로 통해 값을 불러올 수 있다.

이벤트 핸들링

  • 함수 선언시 에로우 화살로 바로 선언 가능하다.
  • 요소에서 적용하기 위해서는 this를 붙여야한다.

함수형 컴포넌트(Functional Component)

클래스형 컴포넌트에 비해서 훨씬 간단하고 단순하지만 state를 관리하지 못한다는 단점으로 인해 잘 사용되지 않았습니다.
하지만 React 16.8 버전에서 Hook 기능이 추가되면서 함수형 컴포넌트에서도 state를 사용할 수 있게 되었고 그 후부터 클래스형 컴포넌트보다는 함수형 컴포넌트가 더 많이 사용되기 시작했습니다.

선언 방식

import React from 'react';
import './App.css';

function App() {
  const name = 'react';
  return <div className = "react">{name}</div>
}

export default App;

특징

  • state, lifeCycle 관련 기능(생명 주기 메서드) 사용 불가능 -> Hook을 통해 해결됨.
  • 메모리 자원을 함수형 컴포넌트보다 덜 사용한다.
  • 컴포넌트 선언이 편하다.
  • return문 사용해서 JSX 반환
  • 클래스형 컴포넌트와 비교해서 훨씬 간결하게 코드를 작성할 수 있다. 함수 자체가 렌더 함수이기 때문에 render() 메서드를 사용하지 않아도 되고, Component를 상속받지 않아도 된다.

기능

  • 함수형 컴포넌트에서는 useState 함수로 state를 사용한다.
  • useState 함수를 호출하면 배열이 반환되는데 첫 번째 원소는 현재 상태
  • 두 번째 원소는 상태를 바꾸어 주는 함수
  • props를 불러올 필요 없이 바로 호출 할 수 있다.
    render함수 parameter로 props를 전달 받아 사용한다.

이벤트 핸들링

  • const 키워드 + 함수 형태로 선언 해야한다.
  • 요소에서 적용하기 위해서는 this가 필요없다.

Class형 컴포넌트 Life cycle


React에서 컴포넌트는 여러 종류의 "생명주기 메소드" 를 가지며 이 메소드를 오버라이딩(상속하여 재정의) 하여 특정 시점에 코드가 실행되도록 설정 합니다.
클래스 컴포넌트에만 해당되는 내용이며, 함수형 컴포넌트는 Hook를 사용하여 생명주기에 원하는 동작을 합니다

Mounting(생성 될 때)

컴포넌트가 인스턴스로 생성되고 DOM 트리에 삽입되어 브라우저상에 나타나는 과정

  • constructor
    컴포넌트의 생성자 메서드, 컴포넌트가 만들어지면 가장 먼저 실행되는 메서드이다.
    시점 : 컴포넌트가 브라우저에 나타나기전 즉, render()전에 호출이되는 라이프 사이클 함수이다.
    사용이유 : 생성자 메서드로 this.state의 초기값 설정, 인스턴스에 이벤트 처리 메서드를 바인딩하기 위해 사용한다.
    super(props)를 첫 줄에 필수로 사용한다.
  • static getDerivedStateFromProps
    시점 : 컴포넌트가 처음 렌더링 되기 전에도 호출 되고 그 이후 리렌더링 되기 전에도 매번 실행됩니다.(render 메서드가 호출되기 직전에 호출되는 라이프 사이클 함수)
    사용이유 : 메소드는 속성값을 이용해서 새로운 상태값을 만들때, props로 받은 값을 state에다가 넣고 싶을때 사용 (거의 쓰지 않는 함수라고 합니다.)
    특징 : 다른 생명주기 메서드와는 달리 앞에 static을 필요로 하고, 정적 메서드이기 때문에 함수 내부에서 this 객체에 접근할 수 없다.
  • render() : 컴포넌트를 렌더링하는 메서드입니다.
    특징 : render 메서드에서는 부수 효과를 발생시키면 안 됩니다. 서버와 통신하기, 브라우저의 쿠키에 저장하기 등은 부수 효과이므로 render 메서드 내부에서는 피해야 한다. 만약 부수 효과가 필요하다면 다른 생명 주기 메서드에서 하면 됩니다.
  • componentDidMount
    시점 : 컴포넌트가 생성된 직후, 트리에 삽입된 직후에 호출됩니다 이 메서드가 호출되는 시점에는 우리가 만든 컴포넌트가 화면에 나타난 상태입니다.
    render 메서드에서 반환한 리액트 요소가 돔에 반영되어야 값을 얻을 수 있기 때문에 해당 컴포넌트에서 필요로 하는 데이터를 요청하기 위해 axios, fetch등을 이용해 외부 api를 호출하는 작업을 진행합니다.
    사용이유 : 외부 라이브러리를 사용하여 특정 DOM에다가 차트를 그릴때,
    컴포넌트에서 필요로하는 데이터 요청, DOM의 속성을 읽거나 직접 변경하는 작업을 할 때 등

Updating (업데이트 할 때)

컴포넌트 props 또는 state가 바뀌었을 때

  • static getDerivedStateFromProps : Mounting 에서 등장한 메서드로 컴포넌트 props나 state가 바뀌는 등 업데이트 할 때도 호출됩니다.

  • shouldComponentUpdate
    시점 : props 또는 state가 새로운 값으로 갱신되어 렌더링이 발생하기 직전에 호출
    사용이유 : 성능(컴포넌트)최적화를 위해 사용한다. 컴포넌트가 리렌더링을 할지 말지 결정하는 메소드이다.
    (함수형 컴포넌트에선 React.memo가 같은 역할을 한다.)
    리액트 공식 홈페이지에서는 이 메소드 대신 PureComponent를 사용하는 것이 좋다고 한다.

shouldComponentUpdate(nextProps, nextState) {
  // return false 하면 업데이트를 안함
  return true;
  // 기본값으로는 true를 반환
}

  • render : Mounting 에서 등장한 메서드로 업데이트에서도 호출됩니다.

  • getSnapshotBeforeUpdate
    시점 : render 메서드 호출 후 브라우저에 나타나기 바로 직전에 호출되는 메서드이다.( 렌더링 결과가 실제 DOM에 반영 되기 직전에 호출 )
    (render() -> getSnapshotBeforeUpdate -> DOM에 변화 반영 -> componentDidUpdate)
    사용이유 : 브라우저에 그리기 전에 스크롤의 위치, DOM의 크기를 사전에 알고 싶을 때, 업데이트 되기 직전에 DOM 함수를 return 시켜가지고 그 return된 값을 componentDidUpdate에서 받을 수 있다
    (메서드가 호출되는 시점에 이전 돔 요소의 상태값을 가져오기 좋다.)

    이 메소드는 사용할 일이 별로 없지만 Hook에서 대체할 수 있는 기능이 아직 없다고 합니다.
    예제) codesandbox.io/s/484zvr87ow?file=/src/index.js 참고

  getSnapshotBeforeUpdate(prevProps, prevState) {
    if (prevProps.color !== this.props.color) {
      return this.myRef.style.color;
    }
    
    return null;
  }
  • componentDidUpdate
    시점 : 리렌더링을 완료한 후 실행되는 메서드이다. 화면에 우리가 원하는 변화가 모두 반영되고 난 뒤 호출 ( Virtual DOM이 실제 DOM에 반영된 후 호출)
    사용이유 :
    새로 반영된 돔의 상태값을 가장 빠르게 가져올 수 있는 메서드입니다.
    컴포넌트가 업데이트 되었을 시에 DOM을 조작하기 위해 사용하거나, 이전과 현재의 props를 비교하여 네트워크 요청을 보내는 작업을 할 때 유용
  componentDidUpdate(prevProps, prevState, snapshot) {
    if (snapshot) {
      console.log("업데이트 되기 직전 색상: ", snapshot);
    }
  }

3번째 파라미터로 getSnapshotBeforeUpdate에서 반환한 값을 조회 할 수 있습니다.

Unmounting (제거 할 때)

컴포넌트가 브라우저상에서 사라질때

  • componentWillUnmount
    시점 : 컴포넌트가 브라우저상에서 사라질때(컴포넌트가 화면에서 사라지기 직전에) 호출된다.
    사용이유 : 주로 DOM에 직접 등록했었던 이벤트를 제거하거나
    setTimeout이 있다면 타이머를 제거, 외부 라이브러리 호출을 제거하기 위해 사용합니다.

컴포넌트 에러가 발생했을때

  • componentDidCatch
    시점 : render 함수에서 에러가 날 때, 에러가 발생할 수 있는 컴포넌트의 부모 컴포넌트에서 작업해야한다.
    사용이유 : 사용자에게는 에러 화면을 보여주고 , 개발자들은 이때 에러 내용을 서버로 전달할 때 사용합니다.

함수형 컴포넌트 LIfe Cycle

💡 해당 함수형 컴포넌트에서는 이전 클래스 컴포넌트와 비교하여 설명하자면, 클래스형 컴포넌트의 라이프사이클 메서드로 사용되었던 constructor(), render(), ComponenDidMount(), componentDidUpdate(), componentWillUnmount()는 함수형 컴포넌트에서 아래와 같이 사용을 하고 있습니다.

💡[ 생명주기 순서 요약 ]
1. 함수형 컴포넌트가 호출이 됩니다.
2. 함수형 컴포넌트의 내부에서 실행합니다.
3. return()으로 화면에 렌더링 합니다.
4. useEffect()가 실행됩니다.

💡 [ 조건부 수행 ]
1. 변경 혹은 컴포넌트의 소멸이 발생 시 useEffect() 실행

💡 [더 알아보기]
1. 렌더링(Rendering) 이란?
React 내에서는 컴포넌트 렌더링이라고도 하며, 컴포넌트 내에 엘리먼트 요소들(HTML, React 사용자 정의 태그)을 화면상에 그리는 동작을 의미한다.

2. 리 렌더링(re-Rendering) 이란?
컴포넌트 내에 엘리먼트 요소들을 코드를 기반으로 화면의 그리는 작업을 다시 수행하는 것을 의미한다.

[Mounting]

컴포넌트 내부

💡 컴포넌트가 호출이 되었을 때 가장 먼저 호출이 되는 것은 컴포넌트 내부입니다. 라이프 사이클 메서드라고 할 수는 없지만 클래스 컴포넌트의 constructor()를 이해하기 위해 설명합니다. 동일하게 State를 정의하거나 사용될 함수들에 대해서 미리 정의를 하는 공간입니다.

/**
 * 함수형 컴포넌트 예시 
 */
const LifecycleFunctionComponent: React.FC = (props: any) => {

    /**
     * 컴포넌트 호출 시 가장 먼저 호출이 되는 공간
     * 컴포넌트에서 사용 될 state나 함수들을 정의 하는 공간입니다.
     */
    console.log("해당 부분이 제일 먼저 호출이 됩니다.");

    const [userInfo, setUserInfo] = useState<any>({
        userId: 'adjh54',
        userAge: 50,
        isShowTempComponent: false,
    });

    return (
        <></>
    )
};
export default LifecycleFunctionComponent;

return()

💡 미리 구현한 HTML를 화면상에 보여주는 메서드입니다.

  • 해당 메서드 안에서는 부모 컴포넌트로 전달받은 props 값의 접근이 가능합니다.
  • constructor()에서 정의한 state 값의 접근이 가능합니다.
  • 해당 공간에서는 setState()를 사용할 수 없습니다.
import React, { useEffect, useState } from "react";

/**
 * 함수형 컴포넌트 예시 
 */
const LifecycleFunctionComponent: React.FC = (props: any) => {

    const [userInfo, setUserInfo] = useState<any>({
        userId: 'adjh54',
        userAge: 50,
        isShowTempComponent: false,
    });

    /**
     * 미리 구현한 HTML를 화면상에 보여주는 메서드이다.
     */
    return (
        <>
            {console.log("Renering ...")}
            <div>
                <h1>Main Function Component 입니다.</h1>
                <div>{userInfo.userAge}</div>
            </div>
        </>
    );

};
export default LifecycleFunctionComponent;

[Mounting/Updating/Unmounting] useEffect()

해당 메서드를 통하여서 Mounting/Updating/Unmounting 처리가 가능합니다.
하나의 컴포넌트 내에서 여러 개 선언이 가능하며, 하나의 메서드로 처리를 해도 무방합니다.

[ 메서드 구조 ]
useEffect( function, deps? );

  • function : useEffect가 수행될 때 실행되는 함수
  • deps [optional] : 배열 형태이며, 의존(dependency) 값을 의미한다.

[Mounting] useEffect()

💡 컴포넌트 내에서 렌더링이 수행된 이후에 실행이 되는 메서드이다.
deps 파라미터를 빈 배열로 수행하면 렌더링이 수행된 이후 최초 한번 수행이 된다.

import React, { useEffect, useState } from "react";
import { LifecycleType } from "./LifecycleType";

/**
 * 함수형 컴포넌트 예시 
 */
const LifecycleFunctionComponent: React.FC = (props: any) => {

    /**
     * 1. 컴포넌트 호출 시 가장 먼저 호출이 되는 공간
     * 컴포넌트에서 사용 될 state나 함수들을 정의 하는 공간입니다.
     */
    console.log("해당 부분이 제일 먼저 호출이 됩니다.");

    const [userInfo, setUserInfo] = useState<LifecycleType>({
        userId: 'adjh54',
        userAge: 50,
        isShowTempComponent: false,
    });

    /**
     * 3. 컴포넌트 내에서 렌더링이 수행된 이후에 실행이 되는 메서드이다.
     * @returns {void}
     */
    useEffect(() => {
        console.log("화면이 렌더링 된 이후에 바로 수행이 됨: componentDidMount()과 동일");
    }, []);

    /**
     * 2. 미리 구현한 HTML(JSX)를 화면상에 보여주는 메서드이다.
     */
    return (
        <>
            {console.log("Renering ...")}
            <div>

                <h1>Main Function Component 입니다.</h1>
                <div>{userInfo.userAge}</div>
            </div>
        </>
    );
};
export default LifecycleFunctionComponent;

[Updating] useEffect()

💡 컴포넌트 내에서 변화가 발생하였을 경우에 실행되는 메서드이다.

  • 변화라 함은 부모 컴포넌트로부터 전달받은 props 값의 변화가 발생하거나 부모 컴포넌트가 리 렌더링이 발생을 하는 경우 수행됩니다.
  • 해당 컴포넌트 내에서 state의 값이 변하는 경우 수행됩니다.
import React, { useEffect, useState } from "react";
import { LifecycleType } from "./LifecycleType";

/**
 * 함수형 컴포넌트 예시 
 */
const LifecycleFunctionComponent: React.FC = (props: any) => {

    /**
     * 컴포넌트 호출 시 가장 먼저 호출이 되는 공간
     * 컴포넌트에서 사용 될 state나 함수들을 정의 하는 공간입니다.
     */
    console.log("해당 부분이 제일 먼저 호출이 됩니다.");

    const [userInfo, setUserInfo] = useState<LifecycleType>({
        userId: 'adjh54',
        userAge: 50,
        isShowTempComponent: false,
    });

    /**
     * 컴포넌트 내에서 변화가 발생하였을 경우에 실행되는 메서드이다.
     */
    useEffect(() => {
        console.log("전달 받은 props의 값에 변화가 생겼을 경우 / 사용자 나이의 변화가 발생하였을 경우 수행이 된다. : componentDidUpdate()와 동일");
    }, [props.appState, userInfo.userAge]);

    /**
     * 미리 구현한 HTML(JSX)를 화면상에 보여주는 메서드이다.
     */
    return (
        <>
            {console.log("Renering ...")}
            <div>

                <h1>Main Function Component 입니다.</h1>
                <div>{userInfo.userAge}</div>
            </div>
        </>
    );

};
export default LifecycleFunctionComponent;

[Unmounting] useEffect()

💡 컴포넌트 내에서 DOM을 제거할 때에 실행이 되는 메서드이다.

  • 컴포넌트의 DOM이 제거될 때 수행이 됩니다. 예를 들어 A라는 컴포넌트 내에서 B라는 컴포넌트를 부르고 있을 전제라고 할 때, B 컴포넌트를 조건부에 따라서 소멸을 시킬 경우 해당 라이프사이클 메서드가 수행이 됩니다.

💡 LifeCycleFunctionComponent이라는 컴포넌트에서 LifeCycleUnmountComponent라는 컴포넌트를 화면상에 보여주고 있습니다. 버튼을 눌렀을 경우 해당 컴포넌트가 제외될 때, LifeCycleUnmountComponent 컴포넌트의 'useEffect()'가 수행되는 것을 확인할 수 있습니다.

import React, { useEffect, useState } from "react";
import { LifecycleType } from "../../type/lifecycle/LifecycleType";

/**
 * 함수형 컴포넌트 예시 
 */
const LifeCycleFunctionComponent: React.FC = (props: any) => {

    const [isShowTempComp, setIsSHowTempComp] = useState<boolean>(true);

    /**
     * 컴포넌트 호출 시 가장 먼저 호출이 되는 공간
     * 컴포넌트에서 사용 될 state나 함수들을 정의 하는 공간입니다.
     */
    console.log("해당 부분이 제일 먼저 호출이 됩니다.");

    const [userInfo, setUserInfo] = useState<LifecycleType>({
        userId: 'adjh54',
        userAge: 50,
        isShowTempComponent: false,
    });

    /**
     * 임시 컴포넌트 Unmount
     */
    const fn_unmountCompoent = () => {
        setIsSHowTempComp(!isShowTempComp);
    }

    /**
     * 미리 구현한 HTML(JSX)를 화면상에 보여주는 메서드이다.
     */
    return (
        <>
            {console.log("Renering ...")}
            <div>
                <h1>Main Function Component 입니다.</h1>
                <button onClick={fn_unmountCompoent}>컴포넌트 제거</button>
                {
                    isShowTempComp && (
                        <LifeCycleUnmountComponent />
                    )
                }
            </div>
        </>
    );
};
export default LifeCycleFunctionComponent;

const LifeCycleUnmountComponent = () => {

    useEffect(() => {
        return () => {
            console.log("LifeCycleUnmountComponent가 Unmount 되었습니다.")
        }
    }, []);

    return (
        <div>
            <h1> Unmount Component</h1>
        </div>
    )

}

JSX

JavaScript Syntax Extension. 리액트에서 사용하는 자바스크립트 확장 문법. JSX로 작성한 코드는 브라우저에서 동작하는 과정에서 바벨을 사용하여 일반 자바스크립트 형태의 코드로 변환됩니다.

JSX 장점

HTML 태그를 그대로 사용하기 때문에 보기 쉽고 익숙합니다.
HTML 태그를 사용하는 동시에 자바스크립트도 JSX 안에서 동작하게 할 수 있습니다.
vs. DOM + Event

JSX 특징

  • 자바스크립트 표현 : { ... javascript... }
  • class vs. className
  • Inline Styling : <div style={{color : "red"}}>Hello React</div>Hello React</div>
  • Self Closing tag : <div></div> vs. <div />
  • 모든 요소를 감싸는 최상위 요소 (cf. React Fragments : <> ... </>)
    : JSX의 큰 특징 중 하나는 내부 요소들을 감싸는 최상위 요소가 있어야 한다고 배웠습니다. Fragments는 DOM에 별도의 노드를 추가하지 않고 하나의 컴포넌트 안에 여러 요소(자식)들을 간단하게 그룹화 할 수 있는 기능입니다. 요소들을 감싸는 div 태그의 불필요한 생성을 막을 수 있어 유용하게 사용됩니다.
    <>
      <div className="loginBtn" onClick={() => console.log("click")}>Login</div>
      <br />
      <div style={{backgroundColor: "grey", height: "10px"}} />
    </>

참고
https://velog.io/@sdc337dc/0.%ED%81%B4%EB%9E%98%EC%8A%A4%ED%98%95-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8
https://born-dev.tistory.com/m/27
https://velog.io/@seong-dodo/React-%ED%81%B4%EB%9E%98%EC%8A%A4%ED%98%95-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-vs-%ED%95%A8%EC%88%98%ED%98%95-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8
https://adjh54.tistory.com/m/43

profile
선명한 기억보다 흐릿한 메모

0개의 댓글