기존 HTML/CSS/JS 방식
처음에는 파일 역할이 명확하게 나뉘어 있었다.
index.html
→ 화면 구조
style.css
→ 디자인
script.js
→ 동작
JavaScript에서는 DOM을 직접 찾고 조작했다.
document.getElementById(...)
document.createElement(...)
appendChild(...)
innerHTML = ''
메모를 추가하거나 삭제한 뒤에는 직접 renderMemos()를 호출해서 화면을 다시 그렸다.
memos.push(newMemo)
renderMemos()
즉, 기존 방식은 다음 흐름이었다.
데이터 변경
→ DOM 직접 조작
→ 화면 직접 갱신
이 방식은 화면이 어떻게 만들어지고 바뀌는지 직접 확인하기 좋았다.
하지만 기능이 늘어날수록 DOM을 직접 다루는 코드가 많아진다.
React 방식으로 바꾸기
React에서는 HTML 역할을 JSX가 담당한다.
기존처럼 index.html에 화면을 직접 작성하는 대신, App.jsx의 return 안에 화면 구조를 작성했다.
return (
<div className="app">
...
</div>
)
JSX는 HTML처럼 보이지만 JavaScript 안에서 사용하는 문법이다.
그래서 HTML의 class는 JSX에서 className으로 작성하고, for는 htmlFor로 작성한다.
<label htmlFor="memo-title">제목</label>
<div className="memo-card"></div>
겉으로는 HTML과 비슷하지만, 실제로는 React 컴포넌트가 반환하는 화면 구조라고 볼 수 있다.
React의 핵심은 state
React에서는 화면에 영향을 주는 데이터를 state로 관리한다.
const [title, setTitle] = useState('')
const [content, setContent] = useState('')
const [memos, setMemos] = useState([])
각 값의 역할은 다음과 같다.
title
→ 현재 제목 입력값
content
→ 현재 내용 입력값
memos
→ 메모 배열
그리고 setTitle, setContent, setMemos는 각각의 state를 바꾸는 함수다.
중요한 점은 React에서는 state가 바뀌면 자동으로 다시 렌더링된다는 것이다.
set 함수 실행
→ state 변경
→ 컴포넌트 다시 실행
→ JSX 다시 계산
→ 화면 갱신
즉, React에서는 화면을 직접 수정하는 것이 아니라 화면의 기준이 되는 데이터를 바꾼다.
입력값 관리
기존 JavaScript에서는 input 값을 직접 꺼냈다.
titleInput.value
React에서는 input을 state와 연결했다.
<input
value={title}
onChange={(event) => setTitle(event.target.value)}
/>
이 흐름은 다음과 같다.
value={title}
→ title 값을 input에 보여준다.
onChange
→ input 값이 바뀔 때 실행된다.
event.target.value
→ 사용자가 input에 입력한 현재 값이다.
setTitle(event.target.value)
→ 입력값을 title state에 저장한다.
방향으로 보면 다음과 같다.
title → input
input → setTitle → title
즉, React에서는 입력값도 state로 관리한다.
메모 추가
기존 JavaScript에서는 배열에 직접 메모를 추가했다.
memos.push(newMemo)
renderMemos()
React에서는 새 배열을 만들어 state를 변경했다.
setMemos([...memos, newMemo])
이 코드는 다음 뜻이다.
기존 memos 배열을 펼친다.
뒤에 newMemo를 추가한다.
새 배열을 만든다.
setMemos로 memos state를 교체한다.
React가 다시 렌더링한다.
React에서는 기존 배열을 직접 수정하기보다, 새 배열을 만들어 state를 바꾸는 방식으로 처리했다.
메모 목록 출력
기존 JavaScript에서는 직접 DOM 요소를 만들었다.
document.createElement('div')
appendChild(memoCard)
React에서는 map()을 사용해서 배열을 화면으로 바꿨다.
{memos.map((memo) => (
<MemoItem
key={memo.id}
memo={memo}
onEditMemo={handleEditMemo}
onDeleteMemo={handleDeleteMemo}
/>
))}
map()은 메모 배열을 돌면서 메모 하나를 화면 요소 하나로 바꿔준다.
또한 key={memo.id}는 React가 목록 항목을 구분하기 위해 사용하는 값이다.
화면에 직접 보이는 값은 아니지만, React가 어떤 항목이 추가되었고 삭제되었는지 구분하는 데 필요하다.
수정과 삭제
삭제는 filter()를 사용했다.
const nextMemos = memos.filter((memo) => {
return memo.id !== id
})
setMemos(nextMemos)
filter()는 조건에 맞는 요소만 남겨 새 배열을 만든다.
삭제하려는 id와 다른 메모만 남기면, 해당 메모가 제외된 새 배열이 만들어진다.
수정은 map()을 사용했다.
const nextMemos = memos.map((memo) => {
if (memo.id === id) {
return {
id: memo.id,
title: newTitle.trim(),
content: newContent.trim(),
}
}
return memo
})
setMemos(nextMemos)
map()은 배열을 돌면서 새 배열을 만든다.
수정할 id와 같은 메모를 만나면 새 제목과 내용으로 바꾼 객체를 반환하고, 나머지는 그대로 반환한다.
삭제와 수정 모두 공통점이 있다.
기존 배열을 기준으로 새 배열을 만든다.
setMemos로 state를 변경한다.
React가 자동으로 화면을 다시 그린다.
localStorage 저장
React에서도 localStorage를 사용해 새로고침 후에도 메모가 유지되도록 했다.
처음 실행될 때 localStorage에서 메모를 불러왔다.
useEffect(() => {
const savedMemos = localStorage.getItem('memos')
if (savedMemos !== null) {
setMemos(JSON.parse(savedMemos))
}
}, [])
그리고 memos가 바뀔 때마다 localStorage에 저장했다.
useEffect(() => {
localStorage.setItem('memos', JSON.stringify(memos))
}, [memos])
정리하면 다음과 같다.
useState
→ 화면에 영향을 주는 데이터 관리
useEffect
→ 렌더링 이후에 실행할 작업 처리
JSON.stringify
→ 배열을 문자열로 변환해 저장
JSON.parse
→ 문자열을 다시 배열로 변환해 불러오기
localStorage는 화면을 그리는 작업이 아니라 브라우저 저장소를 다루는 작업이므로 useEffect에서 처리했다.
컴포넌트 분리
처음에는 App.jsx 안에 모든 코드가 있었다.
이후 역할별로 컴포넌트를 분리했다.
App.jsx
→ state와 기능 관리
MemoForm.jsx
→ 메모 입력 폼
MemoList.jsx
→ 메모 목록
MemoItem.jsx
→ 메모 카드 하나
컴포넌트를 분리하면서 props를 사용했다.
<MemoForm
title={title}
content={content}
onTitleChange={(event) => setTitle(event.target.value)}
onContentChange={(event) => setContent(event.target.value)}
onAddMemo={handleAddMemo}
/>
props는 부모 컴포넌트가 자식 컴포넌트에게 넘겨주는 값 또는 함수다.
흐름은 다음과 같다.
App이 state를 가지고 있다.
MemoForm은 props로 title, content, 함수를 받는다.
MemoForm에서 이벤트가 발생하면 App에서 받은 함수를 실행한다.
App의 state가 바뀐다.
React가 다시 렌더링한다.
즉, 컴포넌트를 분리해도 데이터의 중심은 App에 있고, 하위 컴포넌트는 필요한 값과 함수를 props로 받아 사용한다.
HTML/CSS/JS와 React의 가장 큰 차이
기존 방식은 화면을 직접 조작했다.
HTML/CSS/JS
→ DOM을 직접 찾는다.
→ DOM을 직접 만든다.
→ DOM을 직접 붙인다.
→ 화면을 직접 갱신한다.
React 방식은 state를 기준으로 화면을 그린다.
React
→ state를 바꾼다.
→ React가 컴포넌트를 다시 실행한다.
→ JSX를 다시 계산한다.
→ 화면이 자동으로 갱신된다.
가장 중요한 차이는 이것이다.
기존 JS는 화면을 직접 바꾼다.
React는 state를 바꾸면 화면이 따라온다.
이 차이를 이해하는 것이 이번 React 단계의 핵심이었다.
현재 React 메모장의 기능
현재 React 버전 메모장은 기존 JavaScript 버전에서 만들었던 기능을 대부분 다시 구현한 상태다.
메모 작성
메모 목록 보기
메모 수정
메모 삭제
새로고침 후 유지
컴포넌트 분리
기능 자체는 기존과 비슷하지만, 구현 방식은 달라졌다.
'Project > Memo Evolution' 카테고리의 다른 글
| #18 Java 콘솔 메모장 시작 중 만난 IntelliJ 설정 문제 (0) | 2026.06.20 |
|---|---|
| #17 Java 콘솔 메모장 시작하기 (0) | 2026.06.20 |
| #15 컴포넌트 분리와 props 이해하기 (0) | 2026.06.20 |
| #14 React에서 localStorage로 메모 저장하기 (0) | 2026.06.19 |
| #13 React에서 메모 삭제 기능 구현하기 (0) | 2026.06.18 |