class & function component

seul_velog·2022년 3월 23일
0

React

목록 보기
2/11
post-thumbnail

Props와 State 그리고 Render 함수

Props

컴포넌트 외부에서 컴포넌트에게 주는 데이터


State

컴포넌트 내부에서 변경할 수 있는 데이터 (컴포넌트에 들어있는 데이터를 나타내는 오브젝트)

  • Props, State 둘 다 변경이 발생하면 렌더가 다시 일어날 수 있다.

render

Props와 State를 바탕으로 컴포넌트를 그린다.

  • 어떻게 사용자에게 표기될 것인지 나타내는 함수 (JSX라고 한다.)
  • Props와 State가 변경되면 컴포넌트를 다시 그린다.
    → 성능이 괜찮은 이유는 VDOM 덕분이다.




📍 리액트에서 컴포넌트를 작성하는 방법


✍️ React에서 컴포넌트를 작성하는 방법은 두 가지 이다. 아직 둘 다 잘 모르는 상태에서 두가지 컴포넌트를 동시에 접하다 보니 헷갈리는 개념들이 있어서 두 스타일의 기초적인 부분을 정리해보려고 한다.

1. Class

클래스 문법을 이용해서 컴포넌트를 만든다.

// 정의
class ClassComponent extends React.Component {
  render(){
      return <div>Hello</div>;
  }
}

// 사용
ReactDOM.render(<ClassComponent />, document qeuerySelector('#root'))
  • 모든 기능을 전부 사용할 수 있지만, 클래스 문법을 알아야 하고 코드가 복잡해지는 단점이 있다. 컴포넌트 내부에 state를 만들어 사용한다.



2. Function

함수 문법을 이용해서 컴포넌트를 만든다.

// 정의1
function FunctionComponent(){
  return <div>Hello</div>;
}

// 정의2
// 단순히 엘리먼트만 리턴한다면 {}와 return생략가능
// 즉, 화살표 함수의 유일한 문장이 return이므로 {}와 return생략
const FunctionComponent = () => <div>Hello</div>

// 사용
ReactDOM.render(<FunctionComponent />, document.querySelector('#root'))
  • 함수의 문법으로 작성 가능하며 최근에는 함수 컴포넌트가 가진 단점(기능)이 보완된 Hook 기능이 추가되면서 class스타일의 기능(state와 life cycle)을 가진 컴포넌트를 만들 수 있게 되었다.



✍️ 코드로 비교해보기

ex.1)

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

function App() {
  return (
    <div className="container">
      <h1>Hello world</h1>
      <FuncComp></FuncComp>
      <ClassComp></ClassComp>
    </div>
  );
}

// 1) 함수로 컴포넌트 만들기
function FuncComp() {
  return (
    <div className="container">
      <h2>function style component</h2>
    </div>
  );
}

// 2) 클래스로 컴포넌트 만들기
class ClassComp extends React.Component {
  render() {
    return (
      <div className="container">
        <h2>class style component</h2>
      </div>
    );
  }
}

export default App;

  • 1) 함수로 컴포넌트를 만들 때는 return() 을 이용한다.
  • 2) 클래스로 컴포넌트를 만들 때는 render 라는 이름의 함수 즉, 메소드를 정의 하고 그 리턴값이 UI가 된다.
    → 클래스는 랜더라는 함수를 이용, 함수는 자기 자신이 랜더 함수가 된다.
  • 컴포넌트를 사용하는 쪽 : 컴포넌트가 제공하는 props를 통해서 해당 컴포넌트를 이용할 수 있다
  • 컴포넌트를 만드는 쪽 : 내부적으로 state 라는 데이터를 통해서 내부에 여러 작업들을 할 수 있다.
    - porps는 함수, 클래스 양쪽 다 사용가능, state는 클래스 방식에서만 사용가능 했지만 현재는 함수컴포넌트도 사용할 수 있게 되었다.



ex.2)

function App() {
  return (
    <div className="container">
      <h1>Hello world</h1>
      <FuncComp initNumber={2}></FuncComp> // 0)
      <ClassComp initNumber={2}></ClassComp> // 0)
    </div>
  );
}

function FuncComp(props) {
  return (
    <div className="container">
      <h2>function style component</h2>
      <p>Number : {props.initNumber}</p> // 2)
    </div>
  );
}

class ClassComp extends React.Component {
  render() {
    return (
      <div className="container">
        <h2>class style component</h2>
        <p>Number : {this.props.initNumber}</p> // 1)
      </div>
    );
  }
}

  • 0) props 설정

  • 1) 클래스로 props 받기

  • 2) 함수로 props 받기
    - 함수의 경우 this 를 사용하는 것이 아니고, 함수를 리액트가 호출할 때 첫번째 매개변수의 인자 값으로 전달된 porps 값을 전달하도록 약속되어 있다.

    1. 매개변수를 설정한다. (name은 임의설정 가능) 현재 initNumber={2} 값이 매개변수에 들어있는 상태이다.
    2. 매개변수를 통해서 받는다. {props.initNumber}

❓ 그렇다면 컴포넌트가 내부적으로 자신의 상태를 바꾸고 관리하기 위해서 사용하는 state 는 어떻게 함수 & 클래스 방식에서 사용될까?




클래스에서 state 사용하기

ex.1)

function App() {
  return (
    <div className="container">
      <h1>Hello world</h1>
      <FuncComp initNumber={2}></FuncComp>
      <ClassComp initNumber={2}></ClassComp>
    </div>
  );
}

class ClassComp extends React.Component {
  state = { // 1)
    number: this.props.initNumber, // 2)
  };
  render() {
    return (
      <div className="container">
        <h2>class style component</h2>
        <p>Number : {this.state.number}</p> // 3)
      </div>
    );
  }
}
  • 1) 이전부터 있었던 기능이다. 먼저 초기값을 설정한다.
  • 2) number 라고 하는 state 값을 주고 이때, props 를 통해서 전달된 initNumber 값을 전달한다. (기존에 '2' 숫자의 값이 이부분의 값이 되도록 설정한다.)
  • 이 컴포넌트 안에서의 state는 넘버의 값이 2가 되었다. 이것을 사용하기 위해서 3) 부분을 수정한다.
    → 이전에는 props의 값을 그대로 number의 값으로 찍어주었다면, 이제는 props의 값을 state로 주었기 때문에 state의 값이 바뀔 때마다 랜더가 호출, 바뀐 값이 UI로 바로 확인 된다.

ex.1-2) state 업데이트

이어서 state를 셋팅(초기화) 하고 state의 값을 사용, 변경 하는 작업을 해보자.▼

class ClassComp extends React.Component {
  state = {
    number: this.props.initNumber,
  };
  render() {
    return (
      <div className="container">
        <h2>class style component</h2>
        <p>Number : {this.state.number}</p>
        <input // 1)
          type="button"
          value="random"
          onClick={function () {
            this.setState({ number: Math.random() });
          }.bind(this)} // 2)
        ></input>
      </div>
    );
  }
}

  • 1) input 태그를 추가한다. 버튼을 누르면 setState에 의해서 state의 값이 바뀐다. (랜덤 함수를 통해 랜덤한 숫자로 나타남)
    → state값이 바뀌면서 rander 함수가 호출, 바뀐 결과가 반영된다.
  • 2) bind 를 통해 this를 넣어줘야 한다. (클래스 스타일의 단점이기도 하다🥲)




함수에서 state 사용하기

Hook

1) 기본적으로 리액트가 Hook을 우리에게 공급해주는 내장된 Hook

  • 이름이 use로 시작하는 Hook 은 내장된 훅이다. (페이스북이 우리에게 제공)

2) 직접 만들 수 있는 사용자 정의 Hook


ex.1-1)

function App() {
  return (
    <div className="container">
      <h1>Hello world</h1>
      <FuncComp initNumber={2}></FuncComp>
      <ClassComp initNumber={2}></ClassComp>
    </div>
  );
}

function FuncComp(props) {
  const numberState = useState(); // 1)
  console.log(numberState);

  return (
    <div className="container">
      <h2>function style component</h2>
      <p>Number : {props.initNumber}</p>
    </div>
  );
}
  • 클래스에서 사용한 state 작업을 함수안에서는 훅을 이용해서 똑같이 구현하기.
  • 1) useState라는 함수를 호출한다.
    React.useState 같이 할 수 있지만, 상단 import React, { useState } from "react"; 로 작성해서 간편하게 같은 결과를 얻을 수 있다.
  • 호출해서 만들어진 결과를 numberState에 담아서 확인해보자.
  • ❗️ useState()를 쓰면 무조건 배열이 리턴, 그 배열은 두개의 값으로 이루어진 배열이다.
    • 배열이 가진 첫 번째 값 : 우리가 원하는 state 값
    • 배열이 가진 두 번째 값 : 상태를 바꾸는 함수

ex.1-2)

function FuncComp(props) {
  const numberState = useState(props.initNumber); // 1)
  const number = numberState[0];
  console.log(numberState); // 2)

  return (
    <div className="container">
      <h2>function style component</h2>
      <p>Number : {number}</p>
    </div>
  );
}

  • 1) props를 통해 initNumber 값을 주고 싶을 때는 useState의 첫번째 인자로 그 값을 준다.
  • 2) 콘솔을 통해 확인해 보자.
  • ✍️ 즉, 우리가 state를 만들고 싶다면 useState()에 어떤 값을 전달하면, 우리가 만드는 state의 초기값이 된다. 그렇게 리턴된 값의 첫번째 자리가 그 값이 된다.

ex.1-3) state 업데이트

function FuncComp(props) {
  const numberState = useState(props.initNumber);
  const number = numberState[0];
  const setNumber = numberState[1]; // 1)
  console.log(numberState);

  return (
    <div className="container">
      <h2>function style component</h2>
      <p>Number : {number}</p>
      <input // 2)
        type="button"
        value="random"
        onClick={function () {
          setNumber(Math.random());
        }}
      ></input>
    </div>
  );
}

  • numberState 의 두번째 값이 상태를 바꾸는 함수이다.
  • 1) 이 변수 안에 함수가 담긴다. 그 함수를 통해 넘버의 값을 바꿀 수 있다.
  • 2) 클래스에서 처럼 input 태그부분을 가져와서 함수 컴포넌트에 맞게 수정해준다. this는 필요없으며 setNumber를 통해서 업데이트 한다.

✍️
1. 함수방식에서 state를 만들 때는 react의 useState를 호출한다.
2. 그 state의 인자로는 그 state의 초기값이 온다.
3. useState는 두 개의 값으로 이루어진 배열을 리턴한다.
4. 첫 번째 값은 상태, 두번 째 값은 상태를 바꿀 수 있는 함수이다. (이 값들을 통해서 함수 안에서 state를 사용할 수 있게 되었다.)



📌 클래스 & 함수 컴포넌트에 date 버튼 추가하기

// 함수 컴포넌트
function FuncComp(props) {  
  // 1)
  const numberState = useState(props.initNumber);
  const number = numberState[0];
  const setNumber = numberState[1];

  const dateState = useState(new Date().toString());
  const date = dateState[0];
  const setDate = dateState[1];

  return (
    <div className="container">
      <h2>function style component</h2>
      <p>Number : {number}</p>
      <p>Date : {date}</p>
      <input
        type="button"
        value="random"
        onClick={function () {
          setNumber(Math.random());
        }}
      ></input>

      <input
        type="button"
        value="date"
        onClick={function () {
          setDate(new Date().toString());
        }}
      ></input>
    </div>
  );
}


// 클래스 컴포넌트
class ClassComp extends React.Component {
  state = {
    number: this.props.initNumber,
    date: new Date().toString(),
  };
  render() {
    return (
      <div className="container">
        <h2>class style component</h2>
        <p>Number : {this.state.number}</p>
        <p>Date : {this.state.date}</p>
        <input
          type="button"
          value="random"
          onClick={function () {
            this.setState({ number: Math.random() });
          }.bind(this)}
        ></input>

        <input
          type="button"
          value="date"
          onClick={function () {
            this.setState({ date: new Date().toString() });
          }.bind(this)}
        ></input>
      </div>
    );
  }
}
  • 위의 1) 부분을 간결하게 수정하면 아래와 같이 작성할 수 있다. ▼
  // const numberState = useState(props.initNumber);
  // const number = numberState[0];
  // const setNumber = numberState[1];

  const [number, setNumber] = useState(props.initNumber);

  // const dateState = useState(new Date().toString());
  // const date = dateState[0];
  // const setDate = dateState[1];

  const [date, setDate] = useState(new Date().toString());

📌 컴포넌트로 만들면 좋은 것들 😀 ! (무분별한 컴포넌트화는 좋지 않다고 한다.)

1. 반복적인 html을 축약할 때
2. 큰 페이지들
3. 자주 변경되는 것들

✍️
간단하게 state 사용법의 차이점에 대해서 기초적인 부분만 알아보았는데 이후에 라이프 사이클에 대해서 알게 되면 이부분도 두 형식의 차이점에 대해 정리해야 겠다.
👉 Lifecycle과 useEffect 정리:)

✍️
함수 스타일이 보다 간편할 수 있지만, 많은 문서에서는 아직도 class를 기반으로 된 정보들이 많이 존재하고, 옛날에 만들어진 리액트 라이브러리에서는 아직 Hooks 지원이 안되는 경우가 있다고 한다. 또 클래스도 지속적으로 업데이트될 것이므로, 클래스 컴포넌트에 대한 이해도 꼭 필요할 것이다.🤔




reference
Coding Everybody-react

profile
기억보단 기록을 ✨

0개의 댓글