[리액트] 함수형 컴포넌트와 클래스형 컴포넌트의 차이점

JooSehyun·2023년 2월 6일
0

[Basic]_리액트

목록 보기
1/1
post-thumbnail

React

리액트 컴포넌트는 클래스형 컴포넌트함수형 컴포넌트 로 작성된다.
차이점은 클래스형 컴포넌트state기능 및 생명 주기 함수 기능을 사용할 수 있다는 것과 임의 메서드를 정의할 수 있다는 것.

리액트 16.8버전부터 훅(Hook)이 등장하면서 함수형 컴포넌트에서도 상태값과 생명 주기 함수를 작성 할 수 있게 되었다.

1) 선언 방식

1. 클래스형 컴포넌트

import React, { Component } from 'react';

class App extends Component {
    render() {
        return (
            <div>
                
            </div>
        );
    }
}

export default App;
  • class 키워드 필요
  • 클래스형 컴포넌트에서는 render함수가 있어야 하고, 그 안에서 보여주어야 할 JSX 를 반환해야한다.
  • Component로 상속 받아야 함
  • state , 생명 주기 함수관련 기능사용이 가능
  • props를 조회할 때 this 키워드 사용
  • 함수형 컴포넌트보다 메모리 자원을 더 사용한다.

2. 함수형 컴포넌트

import React from 'react';

const App = () => {
    return (
        <div>
            
        </div>
    );
};

export default App;
  • JSX를 return문을 사용해서 반환

함수형 컴포넌트의 장점

  • 클래스형 컴포넌트보다 선언하기가 훨씬 편하다.
  • 메모리 자원도 클래스형 컴포넌트보다 덜 사용한다.
  • 프로젝트를 완성하여 빌드한 후 배포할 때도 함수 컴포넌트를 사용하는 것이 결과물의 파일 크기가 더 작다. (성능과 파일 크기 면에서 크게 차이는 없다.)

함수형 컴포넌트의 단점

  • state생명 주기 함수 API의 사용이 불가능 (리액트 16.8버전 업데이트 이후 Hooks라는 기능이 도입되면서 해결 클래스형 컴포넌트와 똑같이 사용할 수 있는 것은 아니지만 조금 다른 방식으로 비슷한 작업을 할 수 있게 되었음)

2) state

🕵️‍♀️state : 컴포넌트 내부에서 바뀔 수 있는 값

1. 클래스형 컴포넌트

import React, { Component } from 'react';

class App extends Component {
    constructor(props){
    super(props)
    this.state = {
        test1: [],
        test2: '',
        number: 1
        }
    }
    testFunction = () => {
        this.setState({number : number + 1})
    }
    render() {
        const name = '클래스형 컴포넌트'
        return (
            <div>
             {name}   
            </div>
        );
    }
}

export default App;
  1. constructor안에서 this.state 초기 값 설정 가능
  2. constructor없이도 바로 state 초기 값을 설정가능
  3. this.setState를 통해 state값을 변경
  4. 클래스형 컴포넌트state는 객체형식

2. 함수형 컴포넌트

import React, {useState} from 'react';

const App = () => {
    const [test1, setTest1] = useState([])
    const [test2, setTest2] = useState('')
    const [number, setNumber] = useState(1)

    const testFunction = () => {
        setNumber(number + 1)
    }
    const name = '함수형 컴포넌트'
    return (
        <div>
            {name}
        </div>
    );
};

export default App;
  1. useState함수로 state를 사용한다.
  2. useState함수를 호출하면 배열이 반환되는데 첫 번째 원소는 현재 상태, 두번째 원소는 상태를 바꿔주는 함수이다.

[복습] constructor 는?

constructor(props){
    super(props);
  }

React에서 component를 생성할 때 state값을 초기화 하거나 메서드를 바인딩 할 때 constructor를 사용한다. Reactcomponent 생성자는 해당 component가 마운트 되기 전 호출된다. React.Component를 상속한 컴포넌트의 생성자를 구현할 때 super(props) 사용을 권고하고 있다. 왜냐하면 this.props 사용 시 생성자 내에서 정의되지 않아 버그 발생이 될 수 도 있기 때문
📣 주의 : constructor를 사용할때 생성자 내에서는 setState를 사용하지 말고 this.state로 초기값을 할당한다. (그 외에는 this.setState를 사용)


3) props

🕵️‍♀️props : React가 사용자 정의 컴포넌트로 작성한 엘리먼트를 발견하면 JSX 어트리뷰트와 자식을 해당 컴포넌트에 단일 객체로 전달한다. 이 객체를 props라고 한다.

1. 클래스형 컴포넌트

import React, { Component } from 'react';

class App extends Component {
  render() {
    /* 클래스형 컴포넌트 */
    const {number, testName} = this.props
    return (
      <div>
        {testName}의 나이는 {number}살 입니다.
      </div>
    );
  }
}

export default App;
  • 변수를 만들고 this.props로 통해 값을 불러올 수 있다.

2. 함수형 컴포넌트

import React from 'react';

const App = ({number, testName}) => {
  /* 함수형 컴포넌트 */
  return (
    <div>
      {testName}의 나이는 {number}살 입니다.
    </div>
  );
};

export default App;
  • props를 불러올 필요 없이 바로 호출 할 수 있다.

[복습] props 란?

🕵️‍♀️props : properties(프로퍼티) 의 줄임말이다. 상위 컴포넌트가 하위 컴포넌트에 값을 전달할때 사용한다.
(단방향 부모->자식), 수정 불가능 (자식은 읽기 전용 데이터)

📣사용법

프로퍼티에 문자열을 전달할 때 ""를 사용하여 작성하고, 그외의 값은 {}를 사용한다.

  1. props 지정하기
import React, {Component} from 'react';
import Melon from './component/Melon'

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

export default App;

<Melon/> 컴포넌트를 불러와서 사용하는 부모 컴포넌트 App.js에 넣은 코드이다. <Melon name = "NUYHES Blog"/>propsname의 속성값을 NUYHES Blog로 지정하고 있다.

  1. props 사용하기
import React, { Component } from 'react';

class Melon extends Component {
    render() {
        return (
            <h1>Hello {this.props.name}</h1>
        );
    }
}

export default Melon;

Melon에서는 부모 컴포넌트에서 지정했던 name속성값을 사용 할 수있다. props를 렌더링하기 위해 JSX 내부 {} 안에 작성하고 this.props.name을 사용하여 props의 name속성값에 접근하는 것을 확인할 수 있다.

  1. defaultProps 사용하기

부모 컴포넌트에서 props를 지정하지 않았을 때 defaultProps를 통해 정의한 default 값을 사용할 수 있다.

import React, {Component} from 'react';
import Melon from './component/Melon'

class App extends Component {
  render() {
    return (
      <div className='App'>
        <Melon/>
      </div>
    );
  }
}

export default App;

☝☝이렇게 부모 컴포넌트인 App.js 에서 Melonprops 값을 지정하지 않았을때

import React, { Component } from 'react';

class Melon extends Component {
    render() {
        return (
            <h1>Hello {this.props.name}</h1>
        );
    }
}

Melon.defaultProps = {
    name : "defaultProps입니다."
}

export default Melon;

☝☝ 자식 컴포넌트에 Melon.defaultProps를 만들어 name을 만들어 지정한다.

☝☝ defaultProps를 통해 default 값을 지정하지 않았다면 name : "defaultProps입니다." 값이 나오지 않고 Hello가 나오고 뒤에는 공백일 것이다. (부모 컴포넌트에서 지정하지 않았으므로) 하지만 defaultProps를 통해 name의 default값을 defaultProps입니다.라고 지정한 값을 렌더링해준다.

  1. propTypes를 통한 props 검증하기

propTypes를 통해 부모 컴포넌트로 부터 지정된 props 속성을 검증할 수 있다. 필수로 지정되어야 할 속성이 지정되지 않았거나 특정 type에 대한 props가 다른 type으로 설정되었을 경우에 이를 검증할 수 있는 코드를 작성 할 수 있다. propTypes을 통해 검증코드를 작성하는 방법은 defaultProps 작성법과 비슷하다.

import React, { Component } from 'react';
import propTypes from "prop-types"


class Melon extends Component {
    render() {
        return (
            <h1>Hello {this.props.name}</h1>
        );
    }
}

Melon.propTypes = {
    name : propTypes.string.isRequired
}

export default Melon;

☝☝먼저 propTypes를 사용하기 위해 import한다. 모듈 export코드 위가 바로 propTypes를 통해 props를 검증하는 코드이다. 해석하자면 name 속성은 반드시 부모 컴포넌트에서 지정되어야 하며 Data Typestring으로 지정하라는 의미로 해석할 수 있다.

import React, {Component} from 'react';
import Melon from './component/Melon'

class App extends Component {
  render() {
    return (
      <div className='App'>
        <Melon name = {1}/>
      </div>
    );
  }
}

export default App;

부모 컴포넌트인 App.js에서 일부러 name의 속성을 Number Type으로 지정하고 실행해본다.

브라우저 콘솔에는 nametype이 잘못되었다고 경고해주고 있다.

[출처]https://lktprogrammer.tistory.com/118


4) 이벤트 핸들링

1. 클래스형 컴포넌트

import React, { Component } from 'react';

class App extends Component {
  constructor(props){
    super(props)
    this.state = {
      number:1
    }
  }
  onClickFn = () => {
    this.setState({number : number+1})
  }
  render() {
    return (
      <div>
        <button onClick={this.onClickFn}>버튼</button>
      </div>
    );
  }
}

export default App;
  • 함수 선언시 화살표 함수로 바로 선언이 가능하다.
  • 요소에 적용할때 this.를 붙여줘야한다.

2. 함수형 컴포넌트

import React from 'react';

const App = () => {
  const [number, setNumber] = useState('')
  const onClickFunc = ()=>{
    setNumber(number + 1)
  }
  return (
    <div>
      <button onClick={onClickFunc}>+1 버튼</button>
    </div>
  );
};

export default App;
  • const + 함수 형태로 선언해야 한다.
  • 요소에 적용할때 this가 필요없다.

5) Life Cycle 생명주기

🕵️‍♀️Lift Cycle 이란?

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

1. 클래스형 컴포넌트

1. 생성 될 때 (Mounting)

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

constructor

  • 시점 : 브라우저상에 나타날때 가장 처음 실행되는 함수
  • 사용이유 : 생성자 메서드로 this.state의 초기값 설정, 인스턴스에이벤트 처리 메서드를 바인딩하기 위해 사용한다.
👇예시👇
constructor(props){
	super(props)
    this.state={
    number: 1
    }
}

getDerivedStateFromProps

  • 시점 : 컴포넌트가 처음 렌더링 되기 전에도 호출이 되고 그 이후 리렌더링 되기 전에도 매번 실행된다.
  • 사용이유 : props로 받은 값을 state에다가 넣고 싶을때 사용 (거의 쓰지 않는 함수라고 한다)
👇예시👇
static getDerivedStateFromProps(nextProps, prevState){
	if(prevState.value !== nextProps.value){
    	return{
        	value: nextProps.value
        }
     }
     return null
}

render

  • 컴포넌트를 렌더링하는 메서드이다.
👇예시👇
render(){
  const title = '클래스형 컴포넌트'
  return(
    <div>
      <button onClick={this.onClickFunc}>+1버튼</button>
    </div>
  )
}

componentDidMount

  • 시점 : 컴포넌트가 생성된 직후 트리에 삽입된 직후에 호출된다. 이 메서드가 호출되는 시점에는 우리가 만든 컴포넌트가 화면에 나타난 상태이다.
  • 사용이유 : 외부 라이브러리를 사용하여 특정 DOM에다가 차트를 그릴때, 컴포넌트에서 필요로하는 데이터 요청, DOM의 속성을 읽거나 직접 변경하는 작업을 할 때 등

2. 업데이트 할 때 (Updating)

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

getDerivedStateFromProps

생성 될 때 (Mounting)에서 등장한 메서드로 업데이트에서도 호출이 된다.

shouldComponentUpdate

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

render

생성 될 때 (Mounting)에서 등장한 메서드로 업데이트에서도 호출이 된다.

getSnapshotBeforeUpdate

  • 시점 : render 메소드 호출 후 브라우저에 나타나기 바로 직전에 호출되는 메소드이다.
render()->getSnapshotBeforeUpdate->DOM에 변화 반영->componentDidUpdate)
  • 사용이유 : 브라우저에 그리기 전에 스크롤의 위치, DOM의 크기를 사전에 알고 싶을 때, 업데이트 되기 직전에 DOM 함수를 return 시켜서 그 return된 값을 componentDidUpdate에서 받을 수 있다.
    (이 메소드는 사용할 일이 별로 없지만 Hook에서 대체할 수 있는 기능이 아직 없다고 한다.)

componentDidUpdate

  • 시점 : 리렌더링을 완료한 후 실행되는 메서드이다. 화면에 우리가 원하는 변화가 모두 반영되고 난 뒤 호출
  • 사용이유 : 컴포넌트가 업데이트 되었을 시에 DOM을 조작하기 위해 사용하거나 이전과 현재의 props를 비교하여 네트워크 요청을 보내느 작업을 할 때 유용

3. 제거 할 때 (Unmounting)

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

componentWillUnmount

  • 시점 : 컴포넌트가 브라우저상에서 사라질때
  • 사용이유 : 주로 DOM에 직접 등록했었던 이벤트를 제거하거나 setTimeout이 있다면 타이머를 제거, 외부 라이브러리 인스턴스를 제거하기 위해 사용

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

componentDidCatch

  • 시점 : render 함수에서 에러가 날 때, 에러가 발생할 수 있는 컴포넌트의 부모 컴포넌트에서 작업해야한다.
  • 사용이유 : 사용자에게는 에러 화면을 보여주고, 개발자들은 이때 에러 내용을 서버로 전달할 때 사용한다.
👇예시👇
class App extends Component{
  state = {
    error:false
  }

  componentDidCatch(error, info){
    this.setState({
      error: true
    })
  }
  render(){
    if(this.state.error){
      return<h1>에러</h1>
    }
    return(
      <div>
        <TodoListTemplate form={<From/>}>
          <TodoItemList/>
        </TodoListTemplate>
      </div>
    )
  }
}

export default App

[출처] https://born-dev.tistory.com/27

0개의 댓글