리액트 컴포넌트

애옹이·2026년 8월 17일

리액트

목록 보기
1/1

1. React 컴포넌트란?

React 컴포넌트는 props를 받아서 화면에 그려질 UI(JSX)를 리턴하는, 재사용 가능한 조각 입니다. 버튼 하나, 리스트 아이템 하나처럼 작은 단위일 수도 있고, 여러 컴포넌트를 조합한 페이지 전체일 수도 있어요.

import { useState } from "react";
import ReviewList from "./components/ReviewList";
import Modal from "./components/Modal";
import ReviewForm from "./components/ReviewForm";
import Button from "./components/Button";
import Layout from "./components/Layout";
import mockItems from "./mock.json";
import styles from "./App.module.css";
import useTranslate from "./hooks/useTranslate";

function App() {
  const t = useTranslate();
  const [items, setItems] = useState(mockItems);
  const [order, setOrder] = useState("createdAt");
  const [isCreateReviewOpen, setIsCreateReviewOpen] = useState(false);
  const sortedItems = [...items].sort((a, b) => b[order] - a[order]);

  const handleCreate = (data) => {
    const now = new Date();
    const newItem = {
      id: items.length + 1,
      ...data,
      createdAt: now.valueOf(),
      updatedAt: now.valueOf(),
    };
    setItems([newItem, ...items]);
    setIsCreateReviewOpen(false);
  };

  const handleUpdate = (id, data) => {
    const index = items.findIndex((item) => item.id === id);
    const now = new Date();
    const newItem = {
      ...items[index],
      ...data,
      updatedAt: now.valueOf(),
    };
    const newItems = [...items.slice(0, index), newItem, ...items.slice(index + 1)];
    setItems(newItems);
  };

  const handleDelete = (id) => {
    const nextItems = items.filter((item) => item.id !== id);
    setItems(nextItems);
  };

  return (
    <Layout>
      <div className={styles.buttons}>
        <div>
          <Button
            className={styles.orderButton}
            variant={order === "createdAt" ? "primary" : "ghost"}
            onClick={() => setOrder("createdAt")}
          >
            {t("sort by latest")}
          </Button>
          <Button
            className={styles.orderButton}
            variant={order === "rating" ? "primary" : "ghost"}
            onClick={() => setOrder("rating")}
          >
            {t("sort by best")}
          </Button>
        </div>
        <Button className={styles.createButton} onClick={() => setIsCreateReviewOpen(true)}>
          추가하기
        </Button>
        <Modal isOpen={isCreateReviewOpen} onClose={() => setIsCreateReviewOpen(false)}>
          <h2 className={styles.modalTitle}>리뷰 생성</h2>
          <ReviewForm onSubmit={handleCreate} />
        </Modal>
      </div>
      <ReviewList items={sortedItems} onUpdate={handleUpdate} onDelete={handleDelete} />
    </Layout>
  );
}

export default App;

리액트에서 컴포넌트라는 개념을 사용하는 핵심 이유는 세가지로 볼 수 있습니다.

  1. 재사용성: 한 번 만들어두면 <Layout />처럼 태그 형태로 계속 가져다 쓸 수 있음
  2. 독립성: 컴포넌트마다 자기만의 로직과 상태를 가지고, 서로 조합해서 더 큰 UI를 만들기 가능
  3. 선언적(declarative): "DOM을 이렇게 조작해라" 가 아니라 "지금 상태에서 화면이 이렇게 생겨야 한다"만 기술하면, 실제 반영은 React 내부에서 알아서 처리

컴포넌트는 props를 받아 JSX를 리턴하고, 그게 실제 화면으로 이어지는 흐름


컴포넌트의 형태

리액트 컴포넌트는 두개의 부분으로 나눌 수 있어요. 하나는 정의하는 부분이며, 다른 하나는 사용하는 부분입니다. 정의하는 부분은 function으로 컴포넌트를 만들면서 어떤 props가 필요한지 매개변수 자리를 설계하는 곳이고, 사용하는 부분은 그 컴포넌트를 태그처럼 갖다 쓰면서 실제 값을 채워 넣는 곳이에요.

리액트 컴포넌트의 두가지 형태


함수형 컴포넌트

function Counter() {
  const [count, setCount] = useState(0);

  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

그냥 함수예요. useState, useEffect 같은 훅으로 상태와 생명주기를 관리해요. 훅은 React 16.8(2019년 2월)부터 쓸 수 있게 됐어요.

클래스형 컴포넌트

같은 기능을 클래스형으로 짜면 이렇게 만들어 볼 수 있습니다.

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
    this.handleClick = this.handleClick.bind(this); // this 바인딩 필요
  }

  handleClick() {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return <button onClick={this.handleClick}>{this.state.count}</button>;
  }
}

React.Component를 상속받는 클래스고, 반드시 render()를 구현해야 해요. 상태는 this.state, 업데이트는 this.setState()로 관리해요.

함수형 컴포넌트와 클래스형 컴포넌트의 핵심 차이 네 가지

둘의 차이, 표로 정리하면

함수형 컴포넌트클래스형 컴포넌트
형태함수클래스 (React.Component 상속)
상태 관리useStatethis.state, this.setState()
생명주기useEffect 하나로 대부분 처리componentDidMount 등 여러 메서드로 분산
this신경 안 써도 됨메서드마다 바인딩 필요, 실수하기 쉬움
로직 재사용커스텀 훅으로 간단하게HOC, render props 같은 복잡한 패턴 필요
현재 위치사실상 표준레거시 코드에서 주로 발견됨

왜 함수형이 대세가 됐나?

사실 리액트 초창기엔 상태(state)를 다루려면 무조건 클래스형으로 만들어야 했어요. 그러다 2019년, React가 훅(Hook)을 새로 도입하면서 상황이 바뀌었습니다.

훅이 생기기 전엔, 상태 하나 다루려고 해도 constructor, this.state, render() 같은 클래스 문법을 통째로 알아야 했어요. 근데 훅 덕분에, 위에서 본 것처럼 함수 안에 useState 한 줄만 써도 똑같은 걸 훨씬 짧고 간단하게 만들 수 있게 됐어요.

그래서 요즘 새로 만드는 리액트 프로젝트는 대부분 함수형으로 짜여요. 클래스 문법을 몰라도 리액트를 시작할 수 있게 된 거고, 이에 따라 우리도 처음부터 자연스럽게 함수형과 훅의 형태로 배우고 있는 거예요.

클래스형 컴포넌트의 문제!

클래스형 컴포넌트의 가장 큰 문제는 this 바인딩 문제예요. 클래스형에서는 이벤트 핸들러 안 this가 엉뚱한 걸 가리키는 실수가 흔해서, 매번 .bind(this)를 해주거나 화살표 함수로 우회해야 했어요. 또, 로직 재사용이 훨씬 쉬워요. 함수형과 훅에서는 반복되는 상태 관리 로직을 그냥 커스텀 훅 하나로 뽑아내서 여러 컴포넌트가 나눠 쓸 수 있거든요.


한 줄 요약

  • 컴포넌트: props를 받아 UI를 리턴하는 재사용 단위. 지금은 함수형과 훅 사용이 표준.
profile
풀스택 웹 개발자가 목표인 애옹이

0개의 댓글