HTTP 200 OK

Memento mori & Carpe diem

REACT

Components와 Props

sjoongh 2022. 1. 15. 20:11

개념적으로 컴포넌트는 JS함수와 유사하다. props라고 하는 임의의 입력을 받은 후 화면에 어떻게 표시되는지를 기술하는 React 엘리먼트를 반환한다.

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

컴포넌트를 정의하는 가장 간단한 방법은 JS함수를 작성하는 것이다.

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

이 함수는 데이터를 가진 하나의 "props" (props는 속성을 나타내는 데이터이다.) 객체 인자를 받은 후 React 엘리먼트를 반환하므로 유효한 React 컴포넌트이다. 이러한 컴포넌트는 JS함수이기 때문에 "함수 컴포넌트"라고 호칭한다.

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

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

React의 관점에서 위의 두 가지 컴포넌트는 동일하다. 함수 컴포넌트와 class 컴포넌트 둘 다 몇가지 추가 기능이 존재하며 추후에 설명됨.

컴포넌트 렌더링

이전까지는 DOM 태그만을 사용해 React 엘리먼트를 나타냈다.

const element = <div />;

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

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

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

다음은 페이지에 "Hello, Sara"를 렌더링하는 예시입니다.

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

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

위 예시에서는 다음과 같은 일들이 발생한다.

 

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

  • React는 소문자로 시작하는 컴포넌트를 DOM태그로 처리한다.
  • 예를 들어 <div />는 HTML div태그를 의미하지만, <Welcome />은 컴포넌트를 나타내며 범위 안에 Welcome이 있어야 한다.(vue 컴포넌트 사용법과 동일)
  • 컴포넌트의 이름은 항상 대문자로 시작한다.

컴포넌트 합성

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

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 컴포넌트를 가지고 있다. 하지만 기존 앱에 React를 통합하는 경우에는 Button과 같은 작은 컴포넌트로부터 시작해서 뷰 계층의 상단으로 올라가면서 점진적으로 작업해야 할 수 있다.

컴포넌트 추출

컴포넌트를 여러 개의 작은 컴포넌트로 나눈 것이 중요하다

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'>
        {FormData(props.date)}
      </div>
    </div>
  );
}

이 컴포넌트는 author(객체), text(문자열) 및 date(날짜)를 props로 받은 후 소셜 미디어 웹 사이트의 코멘트를 나타낸다.

이 컴포넌트는 구성요소들이 모두 중첩 구조로 이루어져 있어서 변경하기 어려울 수 있으며, 각 구성요소를 개별적으로 재사용하기도 힘듭니다. 이 컴포넌트에서 몇 가지 컴포넌트를 추출하겠다.

 

먼저 Avatar를 추출하겠습니다.

function Avatar(props) {
  return (
    <img className='Avatar' 
      src={props.user.Avatar}
      alt={props.user.name}
    />
  );
}

Avatar는 자신이 Comment 내에서 렌더링 된다는 것을 알 필요가 없다. 따라서 props의 이름을 author에서 더욱 일반화된 user로 변경하였다.
props의 이름은 사용될 context가 아닌 컴포넌트 자체의 관점에서 짓는 것을 권장합니다.

 

이제 Comment를 단순화 시켜보겠다.

function Comment(props) {
  return (
    <div className='Comment'>
      <div className='UserInfo'>
        <Avatar user={props.autor} />
        <div className='UserInfo-name'>
          {props.autor.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;
}

위와 같은 함수를 순수 함수라고 호칭한다. 입력값을 바꾸려 하지 않고 항상 동일한 입력값에 대해 동일한 결과를 반환한다.

 

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

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

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

물론 애플리케이션 UI는 동적이며 시간에 따라 변화한다. "state"를 통해 위 규칙을 위반하지 않고 사용자 액션, 네트워크 응답 및 다른 요소에 대한 응답으로 시간에 따라 자신의 출력값을 변경할 수 있다.

'REACT' 카테고리의 다른 글

State and Lifecycle  (0) 2022.03.28
webpack 정리  (0) 2022.03.17
babel과 webpack  (0) 2022.01.19
엘리먼트 렌더링이란??  (0) 2022.01.15
JSX란 무엇인가?  (0) 2022.01.15