본문 바로가기
C.W.K.
Stream
Lesson 01 of 07 · published

컴포넌트는 함수, JSX는 문법 설탕

~14 min · components, jsx, fundamentals

Level 0React 입문자
0 XP0/54 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
React 컴포넌트는 element를 반환하는 함수야. JSX는 그 결과를 중첩된 함수 호출 대신 HTML과 닮은 문법으로 표현하게 해 줘.

함수를 넣고 element를 받는다

함수 컴포넌트는 props 객체를 받아 React element를 반환해. 필요하다면 fragment, null, element 배열도 반환할 수 있어. 클래스 상속이나 this, 재정의할 생명주기 메서드는 필요 없어.

React는 화면을 계산할 때 컴포넌트 함수를 호출해. 함수가 돌려주는 값은 UI 자체가 아니라 UI의 설명이고, reconciler가 이전 설명과 비교해 실제 DOM에서 바꿀 부분을 결정해.

JSX는 함수 호출로 바뀐다

JSX는 브라우저가 직접 실행하는 JavaScript 문법이 아니야. Vite의 React 플러그인이 JSX를 react/jsx-runtimejsx()jsxs() 호출로 변환해. 직접 이 함수를 쓸 일은 거의 없지만, 변환 과정을 알면 빌드 오류를 이해하기 쉬워져.

Fragment로 불필요한 wrapper를 피한다

<>...</>는 fragment의 짧은 표기야. DOM에 별도 엘리먼트를 추가하지 않고 여러 자식을 묶을 수 있어. 레이아웃 때문에 쓸모없는 <div>를 만들고 싶지 않을 때 사용해.

자주 쓰는 조건부 렌더링

  • {condition && <Foo />}: 조건이 참일 때만 보여 줘.
  • {condition ? <A /> : <B />}: 두 화면 중 하나를 골라.
  • {items.map(item => <Row key={item.id} {...item} />)}: 목록을 element로 바꿔.

목록 항목에는 안정적인 key가 필요해. React는 key를 보고 이전 항목과 새 항목을 연결해서, 불필요하게 다시 마운트하지 않고 이동하거나 갱신해.

목록이 바뀐다면 배열 index를 key로 쓰지 마. 항목을 재정렬하거나 중간에서 삭제할 때 index는 다른 항목을 같은 것으로 오인하게 해. 입력 상태가 옆 행으로 옮겨 가는 버그를 막으려면 데이터의 안정적인 id를 써.

0이 화면에 나타나는 함정

count가 0일 때 {count && <Badge />}는 숫자 0을 반환하고 React는 그 값을 텍스트로 렌더링해. 배지를 숨기려면 {count > 0 && <Badge />}{Boolean(count) && <Badge />}처럼 결과를 boolean으로 만들어.

Code

같은 컴포넌트의 JSX와 변환된 jsx() 호출 비교하기·tsx
// 본인이 쓰는 것
function Hello({ name }: { name: string }) {
  return (
    <div className="greeting">
      <h1>Hello, {name}</h1>
      <p>Welcome</p>
    </div>
  );
}

// Vite 플러그인이 생성하는 코드 (대략)
import { jsx, jsxs } from "react/jsx-runtime";

function Hello({ name }: { name: string }) {
  return jsxs("div", {
    className: "greeting",
    children: [
      jsx("h1", { children: ["Hello, ", name] }),
      jsx("p", { children: "Welcome" }),
    ],
  });
}
세 조건 패턴이 한 컴포넌트에·tsx
type Item = { id: string; label: string };

function List({ items, loading, error }: {
  items: Item[];
  loading: boolean;
  error: string | null;
}) {
  // Ternary: 두 뷰 중 선택
  if (loading) return <p>Loading…</p>;

  // && 조건식은 값이 참일 때만 오른쪽을 렌더링해.
  return (
    <>
      {error && <p className="text-red-500">{error}</p>}
      {items.length > 0 ? (
        <ul>
          {items.map((item) => (
            // map + 안정적 key
            <li key={item.id}>{item.label}</li>
          ))}
        </ul>
      ) : (
        <p>No items yet.</p>
      )}
    </>
  );
}

External links

Exercise

total, pending, errors 숫자를 받는 Stats 컴포넌트를 만들어. Fragment 안에 세 개의 <p>를 두되 값이 0인 줄은 숨겨. <Stats total={5} pending={0} errors={2} />에서 total과 errors만 보이는지 확인해.
Hint
{pending && <p>...</p>}는 pending이 0일 때 숫자 0을 렌더링해. {pending > 0 && <p>...</p>}처럼 boolean 조건을 만들어.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.