#15 컴포넌트 분리와 props 이해하기

2026. 6. 20. 09:43·Project/Memo Evolution

이번 단계에서는 React 메모장의 기능을 새로 추가한 것이 아니라, 기존 코드를 컴포넌트 단위로 분리했다.

기존에는 App.jsx 안에 모든 코드가 들어 있었다.

입력 폼
메모 목록
메모 카드
추가 함수
수정 함수
삭제 함수
localStorage 처리

처음에는 이렇게 한 파일에 작성하는 것이 이해하기 쉽다.
하지만 코드가 길어질수록 어떤 부분이 입력 폼인지, 어떤 부분이 목록인지, 어떤 부분이 메모 하나인지 구분하기 어려워진다.

그래서 이번 단계에서는 화면 역할별로 컴포넌트를 나누었다.

 

컴포넌트를 분리한 이유

컴포넌트 분리는 기능을 바꾸는 작업이 아니다.
기존에 잘 동작하던 코드를 역할별로 나누는 작업이다.

이번에는 다음처럼 역할을 나누었다.

App.jsx
→ 전체 데이터와 기능 관리

MemoForm.jsx
→ 메모 입력 폼 담당

MemoList.jsx
→ 메모 목록 영역 담당

MemoItem.jsx
→ 메모 카드 하나 담당

즉, 화면을 더 작은 단위로 나누어 관리하기 위한 작업이다.

 

분리 후 파일 구조

이번 단계에서 구조는 다음과 같이 바뀌었다.

src/
 ├─ App.jsx
 ├─ App.css
 └─ components/
     ├─ MemoForm.jsx
     ├─ MemoList.jsx
     └─ MemoItem.jsx

각 파일은 자신의 역할만 담당한다.

MemoForm
→ 제목 입력
→ 내용 입력
→ 메모 추가 버튼

MemoList
→ 메모 목록 전체
→ 메모가 없을 때 안내 메시지

MemoItem
→ 메모 하나의 제목
→ 메모 하나의 내용
→ 수정 버튼
→ 삭제 버튼

이렇게 나누면 화면 구조를 더 쉽게 파악할 수 있다.

 

App.jsx의 역할

컴포넌트를 분리해도 중요한 데이터는 여전히 App.jsx가 가지고 있다.

const [title, setTitle] = useState('')
const [content, setContent] = useState('')
const [memos, setMemos] = useState([])

즉, App.jsx는 메모장의 중심이다.

App.jsx가 담당하는 역할은 다음과 같다.

title state 관리
content state 관리
memos state 관리
메모 추가 함수 관리
메모 수정 함수 관리
메모 삭제 함수 관리
localStorage 저장/불러오기 관리

화면은 여러 컴포넌트로 나누었지만, 실제 데이터와 기능은 App.jsx가 가지고 있다.

 

props란 무엇인가

컴포넌트를 분리하면 한 가지 문제가 생긴다.

예를 들어 title state는 App.jsx에 있는데, 실제 input은 MemoForm.jsx 안에 있다.

그러면 MemoForm은 title 값을 어떻게 사용할 수 있을까?

이때 사용하는 것이 props다.

props
= 부모 컴포넌트가 자식 컴포넌트에게 넘겨주는 값 또는 함수

현재 구조에서는 App이 부모 컴포넌트이고, MemoForm, MemoList, MemoItem은 자식 컴포넌트다.

 

MemoForm에 props 넘기기

App.jsx에서는 MemoForm을 이렇게 사용한다.

<MemoForm
  title={title}
  content={content}
  onTitleChange={(event) => setTitle(event.target.value)}
  onContentChange={(event) => setContent(event.target.value)}
  onAddMemo={handleAddMemo}
/>

이 코드는 MemoForm에게 필요한 값과 함수를 넘겨주는 코드다.

title
→ 제목 input에 보여줄 값

content
→ 내용 textarea에 보여줄 값

onTitleChange
→ 제목 input이 바뀔 때 실행할 함수

onContentChange
→ 내용 textarea가 바뀔 때 실행할 함수

onAddMemo
→ 메모 추가 버튼을 눌렀을 때 실행할 함수

title={title} 이해하기

가장 헷갈렸던 부분은 다음 코드였다.

title={title}

왼쪽과 오른쪽의 의미가 다르다.

왼쪽 title
→ MemoForm에게 넘겨줄 props 이름

오른쪽 {title}
→ App.jsx 안에 있는 title state 값

즉, 이 코드는 다음처럼 이해할 수 있다.

App이 가지고 있는 title state 값을
MemoForm에게 title이라는 이름으로 넘긴다.

예를 들어 App의 title 값이 "오늘 할 일"이라면,

<MemoForm title={title} />

은 개념적으로 이런 느낌이다.

<MemoForm title="오늘 할 일" />

 

MemoForm에서 props 받기

MemoForm.jsx에서는 App에서 넘겨준 props를 이렇게 받는다.

function MemoForm({ title, content, onTitleChange, onContentChange, onAddMemo }) {
  return (
    ...
  )
}

이 코드는 다음과 같은 의미다.

App이 넘겨준 props 중에서
title을 꺼낸다.
content를 꺼낸다.
onTitleChange를 꺼낸다.
onContentChange를 꺼낸다.
onAddMemo를 꺼낸다.

그리고 그 값을 input과 textarea, button에 연결한다.

<input
  value={title}
  onChange={onTitleChange}
/>

<textarea
  value={content}
  onChange={onContentChange}
></textarea>

<button type="button" onClick={onAddMemo}>
  메모 추가
</button>

value={title}의 의미

value={title}

이 코드는 input에 title 값을 넣어서 보여주는 역할을 한다.

방향으로 보면 다음과 같다.

title state → input 화면

즉, title 값을 input에 보여준다.

반대로 사용자가 input에 입력한 값을 title state에 저장하는 코드는 이것이다.

onChange={onTitleChange}

이 함수는 App.jsx에서 이렇게 넘겨준 함수다.

onTitleChange={(event) => setTitle(event.target.value)}

사용자가 input에 입력하면 다음 흐름으로 동작한다.

사용자가 제목 input에 입력
→ onChange 실행
→ onTitleChange 실행
→ event.target.value로 input의 현재 값 가져옴
→ setTitle 실행
→ App의 title state 변경
→ App 다시 렌더링
→ MemoForm에 새 title 전달
→ input value={title}에 새 값 표시

 

값과 함수가 같이 넘어가는 이유

MemoForm은 input 화면을 가지고 있지만, title state는 가지고 있지 않다.

title state는 App.jsx에 있다.

그래서 MemoForm이 input을 제대로 동작시키려면 두 가지가 필요하다.

1. 현재 값을 받아야 한다.
2. 값이 바뀌었을 때 App의 state를 바꿀 함수도 받아야 한다.

그래서 App은 MemoForm에게 값과 함수를 함께 넘긴다.

title={title}
onTitleChange={(event) => setTitle(event.target.value)}

정리하면 다음과 같다.

title
→ 현재 값

onTitleChange
→ 새 값을 title state에 저장하는 함수

 

MemoList 분리

메모 목록도 MemoList.jsx로 분리했다.

App.jsx에서는 이렇게 넘겨준다.

<MemoList
  memos={memos}
  onEditMemo={handleEditMemo}
  onDeleteMemo={handleDeleteMemo}
/>

각 props의 의미는 다음과 같다.

memos
→ 화면에 출력할 메모 배열

onEditMemo
→ 수정 버튼을 눌렀을 때 실행할 함수

onDeleteMemo
→ 삭제 버튼을 눌렀을 때 실행할 함수

중요한 점은 여기서 함수를 실행하는 것이 아니라 넘겨주는 것이다.

onEditMemo={handleEditMemo}

이렇게 써야 한다.

만약 다음처럼 쓰면 안 된다.

onEditMemo={handleEditMemo()}

이렇게 쓰면 클릭했을 때 실행되는 것이 아니라, 렌더링되는 순간 함수가 바로 실행되어 버린다.

 

MemoItem 분리

MemoList 안에서는 memos.map()을 사용해서 메모 하나하나를 MemoItem으로 넘긴다.

{memos.map((memo) => (
  <MemoItem
    key={memo.id}
    memo={memo}
    onEditMemo={onEditMemo}
    onDeleteMemo={onDeleteMemo}
  />
))}

여기서 MemoItem은 메모 하나를 담당한다.

memo
→ 메모 하나의 데이터

onEditMemo
→ 수정 함수

onDeleteMemo
→ 삭제 함수

MemoItem에서는 버튼을 클릭했을 때 현재 메모의 id를 넣어서 함수를 실행한다.

<button type="button" onClick={() => onEditMemo(memo.id)}>
  수정
</button>

<button type="button" onClick={() => onDeleteMemo(memo.id)}>
  삭제
</button>

이렇게 하는 이유는 각 메모마다 id가 다르기 때문이다.

1번 메모 수정 버튼
→ onEditMemo(1)

2번 메모 수정 버튼
→ onEditMemo(2)

3번 메모 수정 버튼
→ onEditMemo(3)

 

현재 컴포넌트 흐름

App
→ title, content, memos state를 가지고 있음
→ 추가/수정/삭제 함수를 가지고 있음

MemoForm
→ App에서 title, content, 입력 변경 함수, 추가 함수를 받음
→ 입력 폼 화면 담당

MemoList
→ App에서 memos, 수정 함수, 삭제 함수를 받음
→ 목록 전체 담당

MemoItem
→ MemoList에서 memo 하나와 수정/삭제 함수를 받음
→ 메모 카드 하나 담당
App
 ├─ MemoForm
 └─ MemoList
      ├─ MemoItem
      ├─ MemoItem
      └─ MemoItem

 

props 흐름 정리

이번 단계에서 가장 중요하게 본 것은 props의 흐름이다.

부모가 state를 가진다.
자식은 props로 받아서 사용한다.
자식에서 이벤트가 발생하면 부모에게서 받은 함수를 실행한다.
부모의 state가 바뀐다.
화면이 다시 렌더링된다.

특히 MemoForm에서 중요한 흐름은 다음과 같다.

App의 title state
→ MemoForm에 title props로 전달
→ input value={title}로 표시
→ 사용자가 입력
→ onTitleChange 실행
→ setTitle로 App의 title state 변경
→ 다시 렌더링

즉, React에서는 값의 흐름을 이렇게 생각하면 된다.

데이터는 부모가 가지고 있고,
자식은 props로 받아서 화면에 사용한다.
자식이 데이터를 바꿔야 할 때는
부모에게서 받은 함수를 실행한다.

 

 

이번 단계의 핵심은 다음과 같다.

컴포넌트 분리
= 화면을 역할별 파일로 나누는 작업

props
= 부모 컴포넌트가 자식 컴포넌트에게 넘겨주는 값 또는 함수

App.jsx는 상태와 기능을 가지고 있고,
MemoForm, MemoList, MemoItem은 각각 필요한 값과 함수를 props로 받아 화면을 담당한다.

 

'Project > Memo Evolution' 카테고리의 다른 글

#17 Java 콘솔 메모장 시작하기  (0) 2026.06.20
#16 HTML/CSS/JS 메모장을 React로 고도화 정리  (0) 2026.06.20
#14 React에서 localStorage로 메모 저장하기  (0) 2026.06.19
#13 React에서 메모 삭제 기능 구현하기  (0) 2026.06.18
#12 React 프로젝트 시작과 입력값 상태 관리  (0) 2026.06.16
'Project/Memo Evolution' 카테고리의 다른 글
  • #17 Java 콘솔 메모장 시작하기
  • #16 HTML/CSS/JS 메모장을 React로 고도화 정리
  • #14 React에서 localStorage로 메모 저장하기
  • #13 React에서 메모 삭제 기능 구현하기
sqaxe1
sqaxe1
woojoo-devlog 님의 블로그 입니다.
  • sqaxe1
    Woojoo's Devlog
    sqaxe1
  • 전체
    오늘
    어제
    • 분류 전체보기 (148)
      • Backend (9)
        • Servlet (7)
        • Spring (2)
      • Frontend (1)
      • CS (0)
      • Book (33)
        • 자바 웹 프로그래밍 Next Step (30)
        • 테스트 주도 개발: 고품질 쾌속개발을 위한 TDD.. (1)
        • 성공과 실패를 결정하는 1%의 네트워크 원리 (2)
      • Engineering (0)
        • Testing (0)
      • Infra (6)
        • AWS (6)
      • Java (4)
      • Network (1)
      • 김영한 (28)
        • 자바 입문 (8)
        • 실전 자바 - 기본편 (6)
        • 실전 자바 - 중급편 (10)
        • 실전 자바 - 고급편 (4)
      • Web (39)
        • Web Basics (39)
      • Project (24)
        • NeoSquare (0)
        • Memo Evolution (24)
      • 정보처리기사 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    aws
    java
    개발서적
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
sqaxe1
#15 컴포넌트 분리와 props 이해하기
상단으로

티스토리툴바