컴포넌트와 props

</>·2022년 1월 16일
3
post-thumbnail

목표

  • 컴포넌트(component)와 props 대해 톺아본다.

3. 컴포넌트(component)와 props

  • 컴포넌트를 정의하는 방법은 함수형 컴포넌트와 클래스형 컴포넌트 2가지가 있다.
// 함수형 컴포넌트
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// 클래스형 컴포넌트
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

3-1. 컴포넌트 렌더링

  • 오로지 DOM 태그만을 사용해 React 엘리먼트를 나타낼 수 있지만
const element = <h1>hello</h1>
  • React 엘리먼트는 사용자 정의 컴포넌트로도 나타낼 수 있다.
const element = <Welcome name="Sara" />;
  • 리액트가 사용자 정의 컴포넌트로 작성한 엘리먼트를 발견하면 JSX 어트리뷰트자식을 해당 컴포넌트에 단일 객체로 전달하는데 이 객체를 props 라고한다.
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);
  • 위 코드에서는 다음과 같은 일들이 일어난다.
  1. Welcome 컴포넌트를 엘리먼트로 ReactDOM.render()를 호출한다.
  2. React는 { name: 'Sara' }를 props로 하여 Welcome 컴포넌트를 호출한다.
  3. Welcome 컴포넌트는 결과적으로 다음 엘리먼트를 반환한다.
    <h1>Hello, Sara</h1> 
  4. 리액트 DOM은 위 엘리먼트와 일치하도록 DOM을 효율적으로 업데이트 한다.

💡 주의

  • 컴포넌트의 이름은 항상 대문자로 시작해야 한다.
  • 리액트는 소문자로 시작하는 div, h1과 같은 컴포넌트를 DOM 태그로 처리한다.
  • 따라서, 사용자 정의 컴포넌트를 만들 때에는 Welcome과 같이 대문자로 먼저 시작해야 한다.

3-2. 컴포넌트의 합성

  • 컴포넌트는 자신의 출력에 다른 컴포넌트를 참조할 수 있다.
  • 이는 모든 세부 단계에서 동일한 추상 컴포넌트를 사용할 수 있음을 의미한다. 즉, 재사용이 가능하다는 것이다.
  • 리액트 앱에서는 버튼, 폼, 다이얼로그, 화면 등의 모든 것들이 흔히 컴포넌트로 표현되고 재사용된다.
  • 예를 들어, Welcome 컴포넌트를 여러 번 렌더링하는 Composition 컴포넌트를 만들 수 있다.
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

function Compoisition(props) {
  return (
    <>
      <Welcome name="Sara" />
      <Welcome name="Cahal" />
      <Welcome name="Edite" />
    </>
  )
}

function App() {
  return (
    <>
      <Compoisition />
    </>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

3-3. 컴포넌트의 추출

  • 다음 Comment 컴포넌트는 author, text, date를 props로 받는다.
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>
  );
}
  • 이 컴포넌트에서 몇 가지 컴포넌트를 추출하면 다음과 같다.
  • 먼저, Avatar라는 컴포넌트를 추출한다면 Avatar는 자신이 Comment 내에서 렌더링 된다는 것을 알 필요가 없다.
  • 따라서, props의 이름을 author에서 더욱 일반화된 user로 변경하는 것이 좋다.
function Avatar(props) {
  return (
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />
  );
}

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <Avatar user={props.author} />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      // 생략
    </div>
  );
}
  • props의 이름은 사용될 context가 아닌 컴포넌트 자체의 관점에서 짓는 것을 권장한다.

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

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

function Comment(props) {
  return (
    <div className="Comment">
      <UserInfo user={props.author} />
    // 생략
    </div>
  );
}
  • 이처럼 컴포넌트를 추출하는 작업은 쉽지 않다.
  • 하지만, 사용 가능한 컴포넌트를 만들어 놓으면 재사용을 할 수 있어 앱의 크기가 커질수록 두각을 나타낸다.

3-4. props

  • 함수 컴포넌트나 클래스 컴포넌트 모두 컴포넌트의 자체 props를 수정해서는 안된다.
function sum(a, b) {
  return a + b;
}
  • 위의 sum 함수는 입력값을 바꾸려 하지 않고 항상 동일한 입력값에 대해 동일한 결과를 반환하는데 이를 순수 함수라고 한다.

순수 함수

  • 외부 상태에 의존하지도 않고 변경하지도 않는, 즉 부수 효과가 없는 함수를 말한다.
  • 즉, 순수 함수는 외부 상태에 전혀 의존하지 않고 매개변수로 전달된 인수에게만 의존해 반환값을 만든다.
function withdraw(account, amount) {
  account.total -= amount;
}
  • 반면에 withdraw 함수는 자신의 입력값을 변경하기 때문에 비순수 함수이다.
  • 리액트에서 정의한 한 가지 엄격한 규칙이 있다.

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

  • 만약 규칙을 위반하지 않고 싶다면 state를 이용해야 한다.

출처

profile
개발자가 되고 싶은 개발자

0개의 댓글