안녕하세요! 개발자 꿈나무 엠디노입니다.
현재 '웹개발 풀스택' 과정을 훈련하고 있습니다.
이번 주차 위클리 페이퍼 주제는 리액트의 효율적인 렌더링을 돕는 Key, 데이터 설계의 기본인 DB 정규화,
그리고 컴포넌트의 일생을 다루는 생명주기(Life Cycle)입니다.
"리액트 리스트에는 왜 꼭 고유한 Key가 필요할까?"
"데이터베이스를 쪼개는 정규화, 실무에선 어떻게 할까?"
"클래스형과 함수형의 생명주기는 어떻게 매칭될까?"
기본부터 실무 활용까지, 7살 아이도 이해할 수 있는 쉬운 비유와 함께 정리해 보았습니다.
💻 이전 포스팅 글은 아래 글을 참고해주세요!
💻 React 컴포넌트 차이와 성능 최적화 Hook 정복 (feat. 왕초보 위클리 페이퍼 #6)
1. React Key: 스마트한 업데이트를 위한 이름표
🔍 상세 설명
리액트에서 key는 리스트 형태의 엘리먼트를 렌더링할 때 항목들을 식별하는 고유한 값입니다.
리액트는 가상 DOM을 비교할 때 이 key를 보고 어떤 항목이 추가, 수정, 삭제되었는지 판단합니다.
만약 key가 없거나 index를 사용하면,
배열의 순서가 바뀔 때마다 리액트가 모든 요소를 새로 그려야 하거나 상태가 꼬이는 버그가 발생할 수 있습니다.
🐣 7살 버전: 유치원 신발장 이름표
유치원 신발장에 똑같은 노란 장화가 10개 있다고 해봐요.
이름표(Key)가 없으면 선생님은 철수 신발을 찾으려고 10개를 다 꺼내서 확인해야 해요.
하지만 이름표를 딱 붙여놓으면? 철수 장화가 젖었을 때 철수 것만 쏙 빼서 말리면 되죠!
리액트도 바뀐 부분만 쏙 찾기 위해 이 이름표가 꼭 필요하답니다.
💻 실무 예시 코드
import React, { useState } from 'react';
// 실무 팁: 데이터베이스에서 가져온 고유 ID(UUID 등)를 사용하는 것이 정석입니다.
const initialUsers = [
{ id: 'user-001', name: '엠디노', role: 'Student' },
{ id: 'user-002', name: '리액트', role: 'Teacher' }
];
function UserProfileList() {
const [users, setUsers] = useState(initialUsers);
// 항목 삭제 시 고유 key가 있으면 리액트가 삭제된 위치를 정확히 파악하여
// 다른 컴포넌트의 불필요한 리렌더링을 막습니다.
const deleteUser = (id) => {
setUsers(users.filter(user => user.id !== id));
};
return (
<ul>
{users.map((user) => (
/* 주의: index(0, 1, 2...)를 key로 쓰면 리스트가 필터링되거나
순서가 바뀔 때 체크박스 선택 등 내부 상태가 엉뚱한 곳에 남는 버그가 생깁니다.
*/
<li key={user.id}>
{user.name} - {user.role}
<button onClick={() => deleteUser(user.id)}>삭제</button>
</li>
))}
</ul>
);
}
2. DB 정규화: 중복 없는 똑똑한 데이터 정리
🔍 상세 설명
데이터베이스 정규화는 중복 데이터를 최소화하고
데이터의 일관성(무결성)을 유지하기 위해 테이블을 논리적으로 쪼개는 과정입니다.
1정규화(원자값), 2정규화(완전 함수 종속), 3정규화(이행 함수 종속 제거) 등을 거칩니다.
이를 통해 데이터를 수정할 때 한 곳만 고쳐도 전체 데이터가 일관되게 유지되는 '이상 현상(Anomaly)' 방지가 목적입니다.
🐣 7살 버전: 장난감 상자 나누기
큰 상자 하나에 자동차와 색종이를 다 섞어 넣으면
자동차 바퀴를 고치고 싶을 때 색종이까지 다 뒤져야 해요.
이걸 '자동차 상자', '색종이 상자'로 따로 나누어 정리하는 게 바로 정규화예요.
자동차가 늘어나도 자동차 상자만 관리하면 되니 섞일 일이 없어 정말 깨끗하겠죠?
💻 실무 예시 코드
-- [1단계] 고객 정보 테이블: 고객의 고유 정보만 담습니다.
CREATE TABLE Users (
user_id INT PRIMARY KEY,
user_name VARCHAR(50),
email VARCHAR(100)
);
-- [2단계] 주문 테이블: 누가(user_id) 주문했는지만 기록합니다. (정규화의 핵심)
-- 만약 여기에 고객 이름까지 넣으면, 고객이 이름을 바꿀 때 모든 주문 기록을 수정해야 하는 번거로움이 생깁니다.
CREATE TABLE Orders (
order_id INT PRIMARY KEY,
user_id INT,
order_date DATE,
FOREIGN KEY (user_id) REFERENCES Users(user_id) -- 외래키로 연결
);
-- [3단계] 실무 팁: '주문'과 '상품'은 별도 테이블로 나누고 '주문상세' 테이블에서 엮어줍니다.
CREATE TABLE OrderItems (
order_id INT,
product_id INT,
quantity INT,
PRIMARY KEY (order_id, product_id)
);
3. 리액트 생명주기: 컴포넌트의 탄생부터 작별까지
🔍 상세 설명
리액트 컴포넌트는 마운팅(생성) -> 업데이트(변화) -> 언마운팅(소멸)의 주기를 가집니다.
1. 클래스형
: constructor(생성), render(그리기), componentDidMount(탄생 직후), componentDidUpdate(수정 직후), componentWillUnmount(사라지기 직전) 메서드를 사용합니다.
2. 함수형
: useEffect 훅 하나로 위 모든 시점을 제어합니다. 의존성 배열(`[]`)에 따라 실행 타이밍이 결정됩니다.
🐣 7살 버전: 화초 키우기
- 마운트: 씨앗을 화분에 심기 (화면 등장)
- 업데이트: 물을 주어 잎이 자라기 (데이터 변화)
- 언마운트: 화초 정리하기 (화면 퇴장)
옛날 방식(클래스형)은 단계마다 도구가 다 달랐지만,
요즘 방식(함수형)은 'useEffect'라는 마법 지팡이 하나면 다 할 수 있어요!
💻 실무 예시 코드 (자세한 설명)
import React, { useState, useEffect } from 'react';
function TimerComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
// [Mount] 클래스형의 componentDidMount 역할
// 컴포넌트가 나타날 때 API를 호출하거나 타이머를 시작합니다.
const timer = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
console.log("🌸 컴포넌트가 나타났습니다!");
// [Unmount] 클래스형의 componentWillUnmount 역할
// 컴포넌트가 사라질 때 메모리 누수를 막기 위해 타이머를 종료(Cleanup)합니다.
return () => {
clearInterval(timer);
console.log("🍂 컴포넌트가 사라졌습니다.");
};
}, []); // 의존성 배열이 []이면 처음과 끝에만 작동
useEffect(() => {
// [Update] 클래스형의 componentDidUpdate 역할
// count 값이 바뀔 때마다 실행되어 특정 로직을 처리합니다.
if(count > 0) console.log(`💧 데이터가 업데이트됨: ${count}`);
}, [count]);
return <div>경과 시간: {count}초</div>;
}
🔥 최종 요약
1. Key: 바뀐 부분만 쏙 찾아주는 고유한 이름표 (ID 사용 필수!)
2. 정규화: 효율적인 데이터 관리를 위해 상자를 나누는 정리정돈
3. 생명주기: 컴포넌트의 일생 관리! 클래스형의 복잡한 과정이 useEffect로 간결해졌다!
이상 개발자 꿈나무 엠디노였습니다...
탄탄한 기본기로 다음 주차에는 더 알찬 내용으로 돌아오겠습니다!
그럼 이만!
'▼ 코딩 공부하기 > ▼▼ 프론트엔드' 카테고리의 다른 글
| [React] 아직도 컴포넌트 하나에 다 넣으세요? (Presentational & Container 패턴) (0) | 2026.01.24 |
|---|---|
| 프론트엔드 취업 치트키: 렌더링 방식 3대장 장단점 및 실무 코드(CSR, SSR, SSG) (2) | 2026.01.18 |
| 💻 React 컴포넌트 차이와 성능 최적화 Hook 정복 (feat. 왕초보 위클리 페이퍼 #6) (0) | 2026.01.03 |
| 💻 React 렌더링 방식과 Virtual DOM 개념 정복 (feat. 왕초보 위클리 페이퍼 #5) (0) | 2025.12.28 |
| 💻 JavaScript 얕은 복사와 깊은 복사, var, let, const 비교 (feat. 왕초보 위클리 페이퍼 #4) (1) | 2025.12.21 |