컴포넌트 기반 구조 (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 |