Published on

리액트 공식문서 스터디 2-1 주차

Authors
  • avatar
    Name
    junyeol kim

Passing Props to a Component


  • 모든 부모 컴포넌트는 Props를 통해 자식 컴포넌트에 정보를 전달할 수 있다.

  • 객체, 배열, 함수 등 모든 JavaScript 값을 Props로 전달할 수 있다.


Familiar props

function Avatar() {
  return (
    <img
      className="avatar"
      src="https://i.imgur.com/1bX5QH6.jpg"
      alt="Lin Lanying"
      width={100}
      height={100}
    />
  )
}

export default function Profile() {
  return <Avatar />
}

  • Props는 JSX 태그에 전달하는 정보입니다. 예를 들어, className, src, alt, width, height<img>에 전달할 수 있는 props 중 일부입니다

  • <img> 태그에 전달할 수 있는 Props는 미리 정의되어 있다. ( ReactDOMHTML 표준을 따른다.)


Passing props to a component

import { getImageUrl } from './utils.js';

{/* 구조 분해 O */}
function Avatar({ size, person }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

{/* 구조 분해 X */}
function Avatar(props) {
  let person = props.person;
  let size = props.size;
  // ...
}

export default function Profile() {
  return (
    <div>
      <Avatar
        size={100}
        person={{
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </div>
  );


  • 자식 컴포넌트에서는 function Avatar({ person, size })처럼 Props를 구조 분해 할당(Destructuring)으로 받는 것이 일반적입니다.

  • 구조 분해를 하지 않고 function Avatar(props)로 받고 props.person 형식으로 접근하는 것도 가능하다.

  • Props를 사용하면 부모와 자식 컴포넌트를 독립적으로 생각할 수 있다.

    • 예를 들어, Profile에서 person이나 size 값을 변경해도 Avatar가 그것들을 어떻게 사용하는지 신경 쓸 필요가 없다. 반대로 Avatar에서 props를 사용하는 방식을 바꿔도 Profile 코드를 볼 필요 없이 변경할 수 있다.

Specifying a default value for a prop

function Avatar({ person, size = 100 }) {
  // ...
}

  • 만약 Props에 값이 지정되지 않았을 때 기본값을 주고 싶다면, 구조 분해 할당에서 파라미터 뒤에 =기본값을 붙이면 된다.

  • 이제 <Avatar person={...} /> 를 size prop 없이 렌더링하면, size의 값은 100이 된다.


    기본값은 size prop이 아예 없거나 size={undefined}일 때만 사용된다. 하지만 size={null}이나 size={0}을 전달하면 기본값은 적용되지 않는다.


Forwarding props with the JSX spread syntax

{
  /* spread 문법 X*/
}
function Profile({ person, size, isSepia, thickBorder }) {
  return (
    <div className="card">
      <Avatar person={person} size={size} isSepia={isSepia} thickBorder={thickBorder} />
    </div>
  )
}

{
  /* spread 문법 O*/
}
function Profile(props) {
  return (
    <div className="card">
      <Avatar {...props} />
    </div>
  )
}

  • spread 문법을 사용하면, Profile의 모든 props가 각각의 이름을 일일이 나열하지 않고 Avatar로 전달된다.

  • 하지만, spread 문법은 신중하게 사용해야한다.


Passing JSX as children

import Avatar from './Avatar.js'

function Card({ children }) {
  return <div className="card">{children}</div>
}

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2',
        }}
      />
    </Card>
  )
}

  • JSX 태그 안에 내용을 중첩하면, 부모 컴포넌트가 그 내용을 children이라는 prop으로 전달받는다. 예를 들어
    위 코드의 <Card />children prop으로 <Avatar />를 받아서, 이를 div로 감싸서 렌더링한다.

  • children prop은 매우 유연하기 때문에, 컴포넌트가 내부적으로 무엇을 받는지 알 필요 없이 다양한 내용을 감싸거나 꾸밀 수 있다.

  • 예를 들어, 레이아웃용 래퍼, 패널, 그리드, 모달 등 다양한 구조의 컴포넌트에서 children을 사용하여 여러 컴포넌트나 텍스트, 이미지 등 어떤 JSX든 자유롭게 포함시킬 수 있다.


How props change over time


  • props는 컴포넌트에 외부에서 전달되는 값이며 항상 고정(static)된 것이 아니라, 렌더링될 때마다 최신 값을 받아올 수 있다.

  • props는 불변(immutable) 이므로 컴포넌트 내부에서 직접 수정할 수 없다.

    • 만약 어떤 값이 바뀌어야 한다면, state(상태)를 사용해 컴포넌트 내부에서 직접 관리해야한다.
  • 결론적으로, props는 외부에서 주기적으로 바뀌어 들어올 수 있지만, 내부에서 직접 변경하지 않고 부모가 새 값을 줄 때마다 갱신되는 일회성 "읽기 전용 데이터" 이다.


Conditional Rendering

  • 리액트에서 "조건부 렌더링"이란 컴포넌트가 상황(상태, props 값, 외부 이벤트 등)에 따라 서로 다른 UI(마크업, 내용, 요소)를 보여주는 방법이다.

Conditionally returning JSX

function Item({ name, isPacked }) {
  if (isPacked) {
    return <li className="item">{name}</li>
  }
  return <li className="item">{name}</li>
}

  • 컴포넌트가 받은 props나 state에 따라 서로 완전히 다른 UI를 반환하고 싶을 땐 자바스크립트의 if문return문을 사용한다.

  • 각각 전혀 다른 JSX를 return

  • 복잡한 케이스 분기에 적합


Conditionally returning nothing with null

function Item({ name, isPacked }) {
  if (isPacked) {
    return null // 안 보임
  }
  return <li className="item">{name}</li>
}

  • 특정 조건에서 아무것도 렌더링하고 싶지 않을 땐, 컴포넌트가 null을 반환하도록 한다. 그렇게 되면 해당 컴포넌트 영역은 아예 DOM에서 비어 있게 된다.

  • 오류 방지/권한 체크/비어있는 데이터 등 최소화 UI에 사용됨

  • 실제로는 부모에서 조건 분기를 하는 패턴이 더 일반적


Conditionally including JSX

{
  /* 삼항 연산자 */
}
function Item({ name, isPacked }) {
  return <li className="item">{isPacked ? name + ' ✅' : name}</li>
}

{
  /* AND(&&) 연산자 */
}
function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✅'}
    </li>
  )
}

  • UI 내부 일부분만 다르게 보여줬으면 좋겠을 때 삼항연산자(? :)와 AND(&&) 연산자를 자주 사용한다.

  • 0, '', NaNfalsy한 값이 조건에 오면 그 값 자체가 렌더링될 수 있음
    null, undefined, false, true는 렌더링이 안된다.
    messageCount > 0 && ... 처럼 boolean 검사 사용 권장한다.


Conditionally assigning JSX to a variable

function Item({ name, isPacked }) {
  let itemContent = name
  if (isPacked) {
    itemContent = <del>{name + ' ✅'}</del>
  }
  return <li className="item">{itemContent}</li>
}

  • 조건과 렌더링이 복잡하거나, JSX가 중복될 때 let 변수를 이용해서 값을 할당한 뒤 JSX 안에 삽입하면 가독성과 유지관리에 유리하다.

Recap


  • 리액트의 조건부 렌더링은 JS의 모든 조건문(if, ? :, && 등)을 활용해 UI를 동적으로 조절 가능하다.

  • UI 전체를 바꿀 땐 if문과 return, 일부만 바꿀 땐 &&/삼항, 코드 효율성을 위해 변수에 JSX 저장 등 다양한 패턴이 있다.

  • 조건부 렌더링은 동적인 현대 웹 환경의 핵심 원리이며, 리액트의 선언적 UI 설계에 필수적인 패턴이다.