컴포넌트 기반 구조 (Component-Based)

컴포넌트 : 독립적인 기능을 수행하는 작은 기능 단위 모듈

• 리액트에서는 모든 페이지가 컴포넌트로 구성

• 하나의 컴포넌트는 또 다른 여러개의 컴포넌트 조합으로 구성될 수 있음.

• 레고 블록을 조립하는 것처럼 컴포넌트를 조합해서 사용

 

함수와 리액트 컴포넌트

• 리액트 컴포넌트는 개념적으로 자바스크립트의 함수와 비슷

• 다만 리액트 컴포넌트는 속성(Props)을 입력 받아 이를 이용해 리액트 엘리먼트를 생성 하여 리턴해 준다는 것이 차이점

 

리액트 컴포넌트

리액트 컴포넌트는 객체지향 프로그래밍(OOP)의 클래스와 인스턴스 개념과 유사

  • 클래스 → 붕어빵 틀 (설계도)
  • 인스턴스(객체) → 실제 만들어진 붕어빵

*리액트에서 컴포넌트는 "붕어빵 틀" 같은 역할을 하고, 이를 사용해 만든 **화면 요소들이 "붕어빵"

 

Props

Props(Properties)는 리액트 컴포넌트의 속성을 뜻함
즉, 컴포넌트에 전달할 **데이터(값)**를 의미

컴포넌트에 전달되는 데이터를 담은 자바스크립트 객체
즉, 하나의 컴포넌트에 다른 props(속재료)를 넣어 다양한 결과를 만들 수 있음

 

*붕어빵 비유

  • 붕어빵 틀(컴포넌트)은 같지만,
    속 재료(Props)에 따라 팥붕, 크림붕, 치즈붕처럼 다양한 붕어빵(엘리먼트)이 나올 수 있음

Props의 특징

읽기 전용(Read-Only)

  • Props는 컴포넌트가 받기만 하고, 직접 수정할 수 없음
  • 붕어빵을 찍는 도중에 속재료를 바꿀 수 없는 것과 같음.

Props 값을 변경하려면?

  • 새로운 Props를 전달해야 함
  • 같은 Props가 들어오면 항상 같은 결과(엘리먼트)가 나와야 함.

 

Props 전달 방식 정리

JSX 문법을 사용하면 키-값 형태로 Props를 전달할 수 있고,
내부적으로는 자바스크립트 객체 형태로 변환

또한, Props의 값으로 컴포넌트도 전달 가능
(즉, 컴포넌트 안에 다른 컴포넌트를 넣을 수도 있음.)

 

 

1. JSX 기반 Props 전달 예시

function App() {
  return (
    <Profile
      name="소품" // name이라는 props에 "소품" 전달
      introduction="안녕하세요, 소품입니다." // introduction props 전달
      viewCount={1500} // 숫자 값도 전달 가능 (문자열 X, 중괄호 사용!)
    />
  );
}

위 코드는 내부적으로 아래처럼 변환됨!

const props = {
  name: "소품",
  introduction: "안녕하세요, 소품입니다.",
  viewCount: 1500
};

 

2. Props 값으로 컴포넌트 전달하기

function App() {
  return (
    <Layout
      width={2560} // width 속성 (숫자 값)
      height={1440} // height 속성 (숫자 값)
      header={
        <Header title="소품의 블로그입니다" /> // header props에 Header 컴포넌트 전달
      }
      footer={<Footer />} // footer props에 Footer 컴포넌트 전달
    />
  );
}

컴포넌트 안에 또 다른 컴포넌트를 props로 넘길 수도 있음

 

 


3. JSX 미사용 - React.createElement() 함수 기반

 

React.createElement() 기본 문법

React.createElement(
  type,         // 요소 타입 (예: 'div', 'span', 컴포넌트 등)
  props,        // 속성 객체 (예: { className: "my-class", id: "my-id" })
  ...children   // 자식 요소 (예: 문자열, 다른 React 요소 등)
);
const profileElement = React.createElement(Profile, {
  name: "소품",
  introduction: "안녕하세요, 소품입니다.",
  viewCount: 1500
});

React.createElement()를 사용하면 JSX 없이도 컴포넌트를 만들 수 있음
하지만 코드가 복잡해지기 때문에 JSX를 주로 사용

 

 

실습(댓글 컴포넌트)
Comment.jsx

import React from "react"; // 리액트 라이브러리 불러오기
import imgUserIcon from "../assets/user_icon.png"; // 사용자 아이콘 이미지 불러오기

// 🟢 함수 컴포넌트(Function Component)
// Comment 컴포넌트는 name(작성자), comment(댓글 내용)을 props로 받아 화면에 표시함
function Comment(props) {
    // 🟢 스타일 객체 정의
    const styles = {
        wrapper: { // 전체 컨테이너 스타일 (댓글 박스)
            margin: 8,
            padding: 8,
            display: "flex", // 가로 정렬
            flexDirection: "row", // 요소들을 가로로 배치
            border: "1px solid grey", // 회색 테두리
            borderRadius: 16, // 테두리를 둥글게
        },
        imageContainer: {}, // 프로필 이미지 컨테이너 (추후 스타일 추가 가능)
        image: { // 프로필 이미지 스타일
            width: 50, // 가로 크기
            height: 50, // 세로 크기
            borderRadius: 25, // 원형 모양
        },
        contentContainer: { // 텍스트 컨테이너 스타일
            marginLeft: 10, // 왼쪽 여백 추가
            display: "flex",
            flexDirection: "column", // 세로 정렬
            justifyContent: "center", // 중앙 정렬
        },
        nameText: { // 이름 스타일
            color: "black",
            fontSize: 16,
            fontWeight: "bold",
        },
        commentText: { // 댓글 내용 스타일
            color: "black",
            fontSize: 16,
        },
    };

    // 🟢 컴포넌트 렌더링 (Rendering)
     return (
        <div style={styles.wrapper}>
            <div style={styles.imageContainer}>
                <img src={imgUserIcon} alt="user icon" style={styles.image} />
            </div>
            <div style={styles.contentContainer}>
                <span style={styles.nameText}>{props.name}</span>
                <span style={styles.commentText}>{props.comment}</span>
            </div>
        </div>
    );
}

export default Comment;

 

CommentList.jsx(여러개의 댓글 보여주는 리스트)

import React from "react"; // 리액트 라이브러리 불러오기
import Comment from "./Comment"; // Comment 컴포넌트 불러오기

// 🟢 함수 컴포넌트(Function Component)
// 여러 개의 Comment 컴포넌트를 조합(컴포넌트 합성)하여 CommentList를 생성
function CommentList(props) {
    return (
        <div> {/* 전체 댓글 리스트 컨테이너 */}
            {/* 🟢 컴포넌트 합성 (Composition) */}
            {/* 여러 개의 Comment 컴포넌트를 조합하여 리스트를 만듦 */}
            <Comment name="홍길동" comment="안녕하세요. 댓글 남깁니다~" /> {/* 첫 번째 댓글 */}
            <Comment name="유재석" comment="리액트 재미있어요~!" /> {/* 두 번째 댓글 */}
            <Comment name="강민경" comment="저도 리액트 배워보고 싶어요!!" /> {/* 세 번째 댓글 */}
        </div>
    );
}

// 🟢 CommentList 컴포넌트 내보내기 (다른 파일에서 사용 가능)
export default CommentList;

 

 

index.js

// React 라이브러리를 불러옴 (React 컴포넌트를 만들기 위해 필요)
import React from 'react';

// ReactDOM을 불러옴 (React 요소를 실제 DOM에 렌더링하는 역할)
import ReactDOM from 'react-dom/client';

// CommentList 컴포넌트를 불러옴 (댓글 목록을 표시하는 컴포넌트)
import CommentList from './components/CommentList';

// HTML 문서에서 id가 'root'인 요소를 찾아 React의 렌더링 루트(root)로 지정
const root = ReactDOM.createRoot(document.getElementById('root'));

// React 컴포넌트를 화면에 렌더링하는 함수
root.render(
  <React.StrictMode> {/* StrictMode는 잠재적인 문제를 감지하고 경고를 표시하는 개발 모드 */}
    <CommentList /> {/* CommentList 컴포넌트를 화면에 렌더링 */}
  </React.StrictMode>
);

*root.render()란?

root.render()는 React 컴포넌트를 실제 화면에 그리는 역할

 

 

실습2(컴포넌트기반스터디룸현황UI 제작)

• 총5개의스터디룸현황표시

• 이미지, 이름, 상태 텍스트 출력

 

 

Room.jsx(방 정보 컴포넌트)

// React 라이브러리를 불러옴 (React 컴포넌트를 만들기 위해 필요)
import React from "react";

// 방 아이콘 이미지 파일을 불러옴
import imgUserIcon from "../assets/room_icon.png";

// Room(방) 정보를 나타내는 컴포넌트
function Room(props) {
    // 스타일을 정의하는 객체
    const styles = {
        wrapper: {
            margin: 20, // 외부 여백
            padding: 8, // 내부 여백
            width: 300, // 가로 크기
            height: 400, // 세로 크기
            display: "flex", // flexbox 사용
            flexDirection: "column", // 세로 방향 정렬
            alignItems: "center", // 가로 중앙 정렬
            justifyContent: "center", // 세로 중앙 정렬
            border: "1px solid grey", // 테두리 추가
            borderRadius: 16, // 모서리를 둥글게
        },
        imageContainer: {
            display: "flex",
            flexDirection: "column",
            alignItems: "center",
        },
        image: {
            width: 100, // 이미지 크기 (가로)
            height: 100, // 이미지 크기 (세로)
            borderRadius: 50, // 둥근 이미지 처리
        },
        contentContainer: {
            marginTop: 15,
            display: "flex",
            flexDirection: "column",
            alignItems: "center",
            justifyContent: "center",
        },
        nameText: {
            marginTop: 30,
            color: "black", // 글자색 검정
            fontSize: 20, // 글자 크기
            fontWeight: "1000", // 글자 두께
            textAlign: "center", // 글자 중앙 정렬
        },
        commentText: {
            marginTop: 30,
            color: "black",
            fontSize: 16,
            fontWeight: "bold",
            textAlign: "center",
        },
    };

    return (
        <div style={styles.wrapper}> {/* 방 정보를 감싸는 컨테이너 */}
            <div style={styles.imageContainer}> {/* 이미지 컨테이너 */}
                <img src={imgUserIcon} alt="room icon" style={styles.image} />
            </div>
            <div style={styles.contentContainer}> {/* 텍스트 정보 컨테이너 */}
                <span style={styles.nameText}>{props.name}</span> {/* 방 이름 */}
                <span style={styles.commentText}>{props.comment}</span> {/* 사용 가능 여부 */}
            </div>
        </div>
    );
}

// Room 컴포넌트를 다른 파일에서 사용 가능하도록 내보내기
export default Room;

 

RoomList.jsx(방 목록을 보여주는 컴포넌트)

// React 라이브러리를 불러옴
import React from "react";

// Room 컴포넌트를 불러옴 (각 방 정보를 표시)
import Room from "./Room";

// RoomList 컴포넌트 정의 (여러 개의 Room을 한 번에 렌더링)
function RoomList(props) {
    return (
        <div> {/* 전체 컨테이너 */}
            <div style={{ display: "flex", flexDirection: "row", flexWrap: "wrap" }}> 
                {/* flexbox를 사용하여 가로 방향으로 나열하고, 줄바꿈 가능하도록 설정 */}
                
                <Room name="[1F] Cube A" comment="사용가능" /> 
                {/* Room 컴포넌트를 사용하여 Cube A 정보를 전달 */}
                
                <Room name="[1F] Cube B" comment="사용가능" /> 
                
                <Room name="[1F] Cube C" comment="사용불가능" /> 
                
                <Room name="[1F] Cube D" comment="사용가능" /> 
                
                <Room name="[1F] Cube E" comment="사용가능" /> 
                
            </div>
        </div>
    );
}

// RoomList 컴포넌트를 다른 파일에서 사용 가능하도록 내보내기
export default RoomList;

 

index.js

// React 라이브러리를 불러옴 (React 컴포넌트를 만들기 위해 필요)
import React from 'react';

// ReactDOM을 불러옴 (React 요소를 실제 DOM에 렌더링하는 역할)
import ReactDOM from 'react-dom/client';

// RoomList 컴포넌트를 불러옴 (방 목록을 표시하는 컴포넌트)
import RoomList from './components/RoomList';

// HTML 문서에서 id가 'root'인 요소를 찾아 React의 렌더링 루트(root)로 지정
const root = ReactDOM.createRoot(document.getElementById('root'));

// React 컴포넌트를 화면에 렌더링하는 함수
root.render(
  <React.StrictMode> {/* StrictMode는 잠재적인 문제를 감지하고 경고를 표시하는 개발 모드 */}
    <RoomList /> {/* RoomList 컴포넌트를 화면에 렌더링 */}
  </React.StrictMode>
);

'React' 카테고리의 다른 글

훅(Hook)  (0) 2025.04.15
리액트JSX  (0) 2025.03.25
소프트웨어 설계 3주차  (1) 2025.03.18
소프트웨어 설계 2주차  (1) 2025.03.18

+ Recent posts