Components and Props

Yeom Jae Seon·2021년 1월 31일
1

React공식문서 공부

목록 보기
3/11
post-thumbnail

컴포넌트란

개념적으로 컴포넌트는 JavaScript 함수와 유사하다.
!! 같다는 말은 아니다. 유사하다.
JavaScript 함수는 인자를 받고 해당 인자로 무언갈 한다.
컴포넌트는 "props"라고 하는 입력을 받고 화면에 어떻게 표시될지 정의된 객체인 React 엘리먼트를 반환 한다.
(두 부분의 차이점을 확실히 하자)

  • 전에 잘못 알았던 지식들
  1. 컴포넌트는 함수이거나 클래스이다.
  2. 컴포넌트는 하나의 기능을 수행하는 UI 단위이다.

1번은 틀린 지식이었고 2번은 맞는 말인데 두루뭉실한 지식이었다.

뭔가 확실한 지식을 얻었다.

  • 컴포넌트란 props라는 입력을 받고 React 엘리먼트를 반환하는 아이를 말한다.

함수 컴포넌트와 클래스 컴포넌트

컴포넌트는 함수로, 클래스로 작성할수 있다.
즉, 함수로 props를 인자로 받고 React Element를 리턴하게 작성할수 있고,
클래스로 props를 입력받아 React Element를 리턴하게 (랜더하게) 작성할수 있다.

더 간단하게 작성하는 방법으론 함수로 컴포넌트를 나타낸다. 이를 함수 컴포넌트라고 한다.

function Greeting(props) {
  return <h1>안뇽, {props.name}</h1>;
}

함수로 표현한 컴포넌트이다. 즉, 함수 컴포넌트
1. props를 입력받는다 = props를 인자로 받음
2. React Element를 리턴한다 = JSX를 return한다. 즉, React Element를 리턴한다.

두부분 모두 충족하므로 위 코드는 컴포넌트인데 함수로 작성했으니 함수 컴포넌트이다.

클래스 컴포넌트는 어떻게생겼나?

class Greeting extends React.Component {
  render() {
    return <h1>안뇽, {this.props.name}</h1>;
  }
}

이렇게 생겼다.
함수컴포넌트는 컴포넌트 정의에 맞게 React Element를 리턴하는데 클래스는 좀다르네?
(이 부분은 다음장 State와 생명주기에서 좀더 알아보자)

아무튼 위의 함수컴포넌트, 클래스 컴포넌트는 React관점에서 동일하다.
(props입력, Element 리턴)

  • 전에 잘못 알았던 지식들
  1. 컴포넌트에는 함수형컴포넌트와 클래스형 컴포넌트가 있다.

수정하자면 컴포넌트를 작성하는 방법으로는 함수로, 클래스로 작성할수있고 전자를 함수 컴포넌트 후자를 클래스 컴포넌트라고 한다.

  • 컴포넌트는 함수로, 클래스로 작성될수 있고 이를 함수컴포넌트, 클래스 컴포넌트 라고 한다.

컴포넌트 렌더링

엘리먼트 렌더링편에서 까진 React 엘리먼트를 DOM 태그로 나타내었다.
ex) const element = <h1>안뇽</h1>

이제부턴 컴포넌트를 배웠으니 React 엘리먼트를 사용자 정의 컴포넌트로 나타낼수 있다.
(컴포넌트는 React 엘리먼트를 반환한다했으니 당연한 말이겠지?)
ex)const element= <Greeting name='재선' />

위에 예시의 사용자 정의 컴포넌트를 React가 발견하게 되면 JSX 속성과 자식 JSX를 props라는 하나의 단일객체에 넣어서 사용자 정의 컴포넌트에 전달하게 된다.
(JSX 에서 속성넣는법 배웠고, JSX는 자식 JSX가 존재할수 있다고 배웠고, JSX는 React Element를 생성한다는것도 배웠지.)

즉, Greeting이라는 사용자 정의 컴포넌트에 props를 전달하는데 props라는 객체에 name이라는 속성과 자식 JSX가 있다면 children이라는 key에 넣어서 전달이된다.
위 예시에는 자식 JSX가 없으니 props객체에 children이라는 key로 전달이 안되겠지?
그럼 예시를 바꿔보면

const element= <Greeting name='재선'>재선이당</Greeting>

children이라는 key에 재선이당이라는 내용이 들어가있는걸 볼수가 있다.

정리하면 엘리먼트를 표현하는 방법에는 DOM 태그와, 컴포넌트가 있다.
컴포넌트로 엘리먼트를 표현할수 있는 이유는 컴포넌트 정의에 입각해서 생각하면 자명한 사실이다.
컴포넌트는 props를 입력받아 Element를 반환한다.
그리고 React가 컴포넌트를 발견하면 컴포넌트에게 JSX 속성값과 자식 JSX들을 props로 전달하게 된다.

이제 본격적으로 컴포넌트를 렌더링 해보자.
즉, 전 시간에했던것처럼 사용자정의컴포넌트(React Element)와 루트 DOM 노드를 ReactDOM.render()함수 인자에 넣으면 되겠지?

import React from "react";
import ReactDOM from "react-dom";

function Greeting(props) {
  return (
    <h1>
      안뇽, {props.name} {props.children}
    </h1>
  );
}
const element = <Greeting name="재선">재선이당</Greeting>;

const rootElement = document.getElementById("root");
ReactDOM.render(element, rootElement);

So EASY~~~
컴포넌트도 엘리먼트를 리턴하므로 엘리먼트와 루트돔노드를 연결하면 React DOM은 엘리먼트(사용자 정의 컴포넌트)를 보고 DOM을 구성하겠지? 물론 효율적으로!
(효율적이란 말은 전시작 마지막에 했던 리액트는 현재 element와 이전 element를 비교해서 실제적으로 변경된 부분만 계산해서 DOM을 구성하므로 효율적이다라는 뜻!)

그래도 공식문서에서도 과정을 설명했으니 나도 해보면
1. 사용자정의 컴포넌트와 루트 돔 노드를 인자로 ReactDOM.render()함수를 호출한다.
2. 사용자 정의 컴포넌트에 props객체가 입력되는데 props에는 namechildren이 존재한다.
3. 사용자 정의 컴포넌트가 리턴한 Element는 그럼 (사실 JSX라고 말하는게 더적절) <h1> 안뇽, 재선 재선이당 </h1>이 될것이다. (React.CreateElement()로 변경해보면 React.createElement('h1', {}, '안뇽, 재선 재선이당');이 되겠지!)
4. 이제 사용자정의컴포넌트에서 리턴한 엘리먼트를 루트 돔노드에 넣어서 ReactDOM은 DOM을 구성하게 된다!

주의!
컴포넌트 이름지을때 대문자로해라. 소문자면 리액트는 DOM 태그인줄 착각한다..

  • 사용자 정의 컴포넌트를 React가 보면 props에 JSX 속성과, 자식 JSX를 넣어 사용자 정의 컴포넌트에 입력한다.
  • 컴포넌트도 Element를 리턴하기 때문에 DOM태그만으로 표현된 Element를 랜더링하는 것과 다르지않다. (ReactDOM.render())

컴포넌트 합성

이부분은 너무어렵게 생각할필요가없다. 말만 어렵다.
사용자정의 컴포넌트에서 리턴하는 곳에 또 다른 사용자정의 컴포넌트를 넣는다는말이다.
이게 어렵나?
그치만 중요하다. 컴포넌트 추출에서 사용할것이기 때문이다.

import React from "react";
import ReactDOM from "react-dom";

function Greeting(props) {
  return (
    <h1>
      안뇽, {props.name} {props.children}
    </h1>
  );
}

function App(props) {
  return (
    <div>
      {props.title}에게 인사!
      <Greeting name="재선" />
      <Greeting name="릴리" />
      <Greeting name="코코" />
    </div>
  );
}
const element = <App title="내 친구들" />;

const rootElement = document.getElementById("root");
ReactDOM.render(element, rootElement);

App 사용자 정의 컴포넌트 리턴하는 부분(Element리턴하는 부분)에 Greeting컴포넌트 세개를 집어넣었다.
(이게 가능한건 컴포넌트가 Greeting함수라 리턴하는게 Element이고 그렇게되면 결국 App컴포넌트도 리턴하는 게 Element가 되니 App은 컴포넌트의 본질을 떠나지 않기 때문이다.)

  • 컴포넌트 내에서 다른 컴포넌트를 리턴하는건 가능하다.
  • 컴포넌트는 Element를 리턴하기 때문에 가능한 것이다.

컴포넌트 추출

위에서 배웠던 컴포넌트 합성을 통해 추출도가능하다.
컴포넌트 추출도 말만어렵지 여러개의 컴포넌트나 DOM태그를 하나의 컴포넌트로 묶는다는 말이다.
일단 이 컴포넌트 추출이 필요한 이유를 먼저 얘기하면 컴포넌트 구조를 단순하게 만들기 위해서이다.!!

사용자 정의 컴포넌트가 하나도없이 DOM태그로만 이루어진 JSX를 리턴하는 (Element를 리턴하는) 컴포넌트의 예시를 보자.

import React from "react";
import ReactDOM from "react-dom";

function Introduce(props) {
  return (
    <div>
      <h1>{props.name}</h1>
      <article>
        <p>나이 : {props.info.age}</p>
        <p>생년월일 : {props.info.birth}</p>
        <p>성별 : {props.info.sex}</p>
        <p>좋아하는 음식 : {props.info.food}</p>
      </article>
      <footer>
        깃헙 주소: <a href={props.subInfo.github}>{props.subInfo.github}</a>
        <br />
        이메일 주소: <a href={props.subInfo.email}>{props.subInfo.email}</a>
      </footer>
    </div>
  );
}
const element = (
  <Introduce
    name="염재선"
    info={{ age: 26, birth: 1996, sex: "male", food: "딲뽂이" }}
    subInfo={{
      github: "https://github.com/YeomJaeSeon",
      email: "a89541457@gmail.com"
    }}
  />
);

const rootElement = document.getElementById("root");
ReactDOM.render(element, rootElement);

Introduce 컴포넌트 를 좀더 간단하고 눈에보기좋게 바꿀순없을까?
이때 컴포넌트 추출을 사용하면된다.
일단 나이, 생년월일 등등을 하나로 묶으면 어떨까?

function Introduce(props) {
  return (
    <div>
      <h1>{props.name}</h1>
      <Info info={props.info}/>
      <footer>
        깃헙 주소: <a href={props.subInfo.github}>{props.subInfo.github}</a>
        <br />
        이메일 주소: <a href={props.subInfo.email}>{props.subInfo.email}</a>
      </footer>
    </div>
  );
}

헉 한눈에 봐도 깔끔해졌다.
이제 footer DOM 태그도 사용자 정의 컴포넌트로 바꿔볼까?

function Introduce(props) {
  return (
    <div>
      <h1>{props.name}</h1>
      <Info info={props.info} />
      <SubInfo subInfo={props.subInfo} />
    </div>
  );
}

완전 단순해지고 깔끔해졌다.
복잡하고 길던 DOM태그만으로 이루어져있던 부분을 사용자정의 컴포넌트로 묶어서 깔끔하게 만들었다.
코드가 비교적 간단하지만 복잡할수록 이 효능이 빛을 발할 것이다.

  • 복잡한 컴포넌트 구조를 컴포넌트 추출을 이용해, 즉 사용자정의 컴포넌트를 만들면 간단하게 만들수있다.

props는 읽기전용

함수컴포넌트나 클래스 컴포넌트 모두에서 입력받은 props를 변경하면 안된다.
이건 규칙이다.
규칙은 외워야한다.
그냥 해야한다.
너이름이 뭐야? '염재선'입니다.
이유가 뭔데? 그냥 그렇게 정해졌다.
마찬가지다. 컴포넌트에서 입력받은 props를 변경해선 안된다.

function sum(a, b){
  return a + b;
}

이런 입력받은 인자를 변경하지않는 함수를 순수함수이다.
순수함수는 입력값이 동일하면 출력값도 동일하다.

컴포넌트도 마찬가지이다.

function Info(props) {
  return (
    <article>
      <p>나이 : {props.info.age}</p>
      <p>생년월일 : {props.info.birth}</p>
      <p>성별 : {props.info.sex}</p>
      <p>좋아하는 음식 : {props.info.food}</p>
    </article>
  );
}

이런식으로 입력받은 props를 변경하면안되고 읽고 그에대한 Element만 리턴해주면된다.

  • 컴포넌트는 입력받은 props를 절대절대 수정하면 안된다. 컴포넌트에게 props는 읽기 전용이다.

위 내용은 React 공식문서를 보고 공부한 내용입니다.
https://ko.reactjs.org/docs/components-and-props.html

1개의 댓글