상세 컨텐츠

본문 제목

Components and Props - React

Programming/React

by 쌩우 2019. 6. 11. 15:16

본문

component를 통하여 UI를 재사용 가능한 별개의 조각조각들로 나누고, 각 조각을 개별적으로 살펴볼 수 있게 된다.
개념적으로 component는 Javascript의 함수와 유사하다. "props" 라고 하는 임의의 입력을 받은 후, 화면에 어떻게 표시되는지를 기술하는 React element를 반환한다.

functional components & class components

component를 정의하는 가장 간단한 방법은 Javascript 함수를 작성하는 것이다.

function Welcome(props) {
    return <h1>Hello, {props.name}</h1>
}

props는 속성을 나타내는 데이터이다.
위의 함수 Welcome은 데이터를 가진 하나의 props 객체 인자를 받은 후 React element를 반환하므로 유효한 React component이다.
이런 component는 Javscript 함수이기 때문에,
말 그대로 함수 컴포넌트라고 부른다.

또한 ES6 class를 사용해 컴포넌트를 정의할 수 있다.

class Welcome extends React.component {
    render() {
        return <h1>Hello, {this.props.name}</h1>;
    }
}

React의 관점에서 위 두 가지 유형의 component는 동일하다.
class는 몇 가지 추가 기능이 있긴 하다.

컴포넌트 렌더링

React 엘리먼트는 사용자 정의 컴포넌트로도 나타낼 수 있다.

const element = <Welcome name="Swoo" />;

React가 사용자 정의 컴포넌트로 작성한 엘리먼트를 발견하면,
JSX attribute를 해당 컴포넌트에 단일 객체로 전달한다.
이 때의 이 객체를 props라고 한다.

페이지에 "Hello, Swoo"를 렌더링하는 예시를 보자.

function Welcome(props) {
    return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Swoo" />;
ReactDOM.render(
    element,
    document.getElementById('root')
);

위의 예시에서는 다음과 같은 일들이 일어난다.

  1. <Welcome name="Sara" /> 엘리먼트로 ReactDOM.render()를 호출한다.
  2. React는 {name: 'Swoo'}를 props로 하여 Welcome 컴포넌트를 호출한다.
  3. Welcome 컴포넌트는 결과적으로 <h1>Hello, Sara</h1> 엘리먼트를 반환한다.
  4. React DOM은 <h1>Hello, Sara</h1> 엘리먼트와 일치하도록 DOM을 효율적으로 업데이트다.

컴포넌트 합성

컴포넌트는 자신의 출력에 다른 컴포넌트를 참조할 수 있다. 이는 모든 세부 단계에서 동일한 추상 컴포넌트를 사용할 수 있음을 의미한다. React 앱에서는 버튼, 폼, 다이얼로그, 화면 등 모든 것들이 흔히 컴포넌트로 표현된다.

예를 들어 Welcome을 여러번 렌더링하는 앱 컴포넌트를 만들 수 있다.

function Welcome(props) {
    return <h1>Hello, {props.name}</h1>;
}

function App() {
    return (
        <div>
            <Welcome name="Sara" />
            <Welcome name="Cahal" />
            <Welcome name="Edite" />
        </div>
    );
}
ReactDOM.render(
  <App />,
  document.getElementById('root')
);

일반적으로 새 React 앱은 최상위에 단일 App component를 가지고 있다.
하지만 기존 앱에 React를 통합하는 경우 Button과 같은 작은 컴포넌트부터 시작해서
뷰 계층의 상단으로 올라가면서 점진적으로 작업해야 할 수 있다.

컴포넌트 추출

컴포넌트를 여러 개의 작은 컴포넌트로 나누는 것을 두려워하지 말아요.
다음의 Comment 컴포넌트를 살펴보자.

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <img className="Avatar"
          src={props.author.avatarUrl}
          alt={props.author.name}
        />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

위의 컴포넌트는 author(객체), text(문자열), date(날짜)를 props로 받은 후 소셜 미디어 웹 사이트의 코멘트를 나타낸다.
이 컴포넌트는 구성요소들이 모두 중첩 구조로 이루어져 있어 변경하기 어려울 수 있으며,
각 구성요소를 개별적으로 재사용하기도 힘들다.
이 컴포넌트에서 몇 가지 컴포넌트를 추출하도록 한다.

  1. 먼저 Avatar를 추출한다.
     funciton Avatar(props) {
         return (
             <img className="Avatar"
               src={props.user.avatarUrl}
               alt={props.user.name}
             />
             );
     }
     //Avatar는 자신이 Comment 내에서 렌더링 된다는 걸 알 필요가 없다.
     //따라서 props의 이름을 author에서 더욱 일반화된 user로 변경하였다.
     //props의 이름은 사용될 context가 아닌 컴포넌트 자체의 관점에서 짓는 것을 권장한다.
    

이제 comment가 살짝 단순해졌다.

unction Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <Avatar user={props.author} />          
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

다음은 Avatar 옆에 사용자의 이름을 렌더링하는 UserInfo 컴포넌트를 추출한다.

function UserInfo(props) {
    return (
        <div className="UserInfo">
        <Avatar user={props.user} />          
        <div className="UserInfo-name">
          {props.user.name}
        </div>
      </div>
    )
}     

이로써 comment는 더욱 단순해졌다.

function Comment(props) {
  return (
    <div className="Comment">
      <UserInfo user={props.author} />
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

처음에는 컴포넌트 추출 작업이 지루해 보일 수 있으나, 재사용 가능한 컴포넌트를 만들어 놓는 것은 더 큰 앱에서 작업할 때 두각을 나타낸다.
UI 일부가 여러 번 사용되거나(Button, Panel, Avatar) UI 일부가 자체적으로 복잡한(App, FeedStory, Comment) 경우에는 재사용 가능한 컴포넌트로 만드는 것이 좋다.

props는 읽기 전용

함수 컴포넌트나 클래스 컴포넌트 모두 컴포넌트의 자체 props를 수정해서는 안 된다.
다음 sum 함수를 보자.

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

이런 함수들은 pure function(순수 함수) 라고 호칭한다.
입력값을 바꾸려 하지 않고 항상 동일한 입력값에 대해 동일한 결과를 반환하기 때문이다.

반면, 다음 함수는 자신의 입력값을 변경하기 때문에 순수 함수가 아니다.

function withdraw(account, amount) {
    account.total -= amount;
}

React는 매우 유연하지만 한 가지 엄격한 규칙이 있다.

모든 React 컴포넌트는 자신의 props를 다룰 때 반드시 순수함수처럼 동작해야 한다!!!

'Programming > React' 카테고리의 다른 글

recast.ly - React  (0) 2019.06.14
checkpoints in react  (0) 2019.06.14
Rendering Elements - React  (0) 2019.06.11
JSX - React  (0) 2019.06.11
React를 배우는 목적  (0) 2019.06.11

관련글 더보기

댓글 영역