배열 메서드, 구조 분해, 스프레드, 클래스 챕터
딥다이브 요약 GitHub
안녕하세요. 9주차입니다. 다음 주부터 React를 시작합니다. React 코드를 처음 열면 거의 모든 줄에서 이번 주에 다루는 문법들이 등장합니다. 개념을 암기하기보다는 언제, 왜 쓰는지에 집중하며 읽어보세요. 이번 주 내용을 자연스럽게 읽을 수 있다면, 다음 주 React 코드가 훨씬 편하게 느껴질 것입니다.
아래 10문제를 막힘없이 풀 수 있다면,
이번 주 학습 자료를 생략하거나, 모르는 부분만 선택적으로 읽으셔도 좋습니다.
바로 하단의 본문 섹션들을 확인해보세요.
고차함수(Higher-Order Function)는 함수를 인자로 받거나 반환하는 함수입니다. 배열 메서드 중 React에서 가장 자주 사용하는 세 가지를 살펴봅니다.
map은 배열의 각 요소에 콜백 함수를 적용하고,
변환된 값으로 이루어진 새 배열을 반환합니다. 원본 배열은
변경되지 않습니다.
const numbers = [1, 2, 3, 4, 5];
// 각 요소를 2배로
const doubled = numbers.map((n) => n * 2);
// [2, 4, 6, 8, 10]
// 객체 배열에서 특정 값만 추출
const users = [
{ id: 1, name: "철수" },
{ id: 2, name: "영희" },
];
const names = users. user
React에서는 배열 데이터를 화면에 렌더링할 때 map을 사용합니다. 아래 코드는
다음 주부터 매일 보게 될 패턴입니다.
// React에서 리스트 렌더링 — 다음 주부터 이 패턴을 매일 씁니다
function UserList({ users }) {
return (
<ul>
{users.map((user) => (
<UserCard key={user.id} {...user} />
))}
</ul>
);
}
filter는 콜백이 true를 반환하는 요소만 모아 새 배열을
반환합니다.
const products = [
{ name: "사과", price: 1000 },
{ name: "한우", price: 50000 },
{ name: "배", price: 2000 },
];
// 1만원 이하 상품만
const affordable = products.filter((p) => p.price <= 10000);
// [{ name: "사과", ... }, { name: "배", ... }]
reduce는 배열의 각 요소를 순회하며 하나의 값으로 누적합니다. 합계 계산,
그룹핑 등에 사용됩니다.
const cart = [
{ name: "사과", price: 1000, qty: 2 },
{ name: "배", price: 2000, qty: 1 },
];
// 총 금액 계산
const total = cart.reduce((acc, item) => acc + item.price * item.qty, 0);
// 1000*2 + 2000*1 = 4000
// reduce로 객체 만들기 (그룹핑)
const byName cart
map, filter, reduce는 모두 새 배열(또는 값)을 반환하므로, 점(.)으로
이어서 조합할 수 있습니다.
const scores = [85, 42, 93, 67, 55, 78, 91];
// 70점 이상인 점수만 골라 평균 구하기
const passing = scores.filter((s) => s >= 70); // [85, 93, 67, 78, 91]
const avg = passing.reduce((sum, s) => sum + s, 0) / passing.length;
// 82.8
const arr = [1, 2, 3, 4, 5];
arr.find((n) => n > 3); // 4 — 조건에 맞는 첫 번째 요소
arr.findIndex((n) => n > 3); // 3 — 조건에 맞는 첫 번째 인덱스
arr.some((n) => n > 4); // true — 하나라도 조건 충족
arr.every((n) => n > 0); // true — 모두 조건 충족
arr
구조 분해 할당(Destructuring)은 배열이나 객체에서 원하는 값을 변수로 한 번에 꺼내는 문법입니다. React에서 props, useState, API 응답 처리 등 어디서나 사용합니다.
const user = { name: "철수", age: 25, role: "admin" };
// 원하는 프로퍼티만 변수로 추출
const { name, age } = user;
// name="철수", age=25
// 다른 이름으로 받기
const { name: userName } = user;
// userName="철수"
// 기본값 지정 — 프로퍼티가 없으면 기본값 사용
const { name = "익명" } = {};
// name="익명"
// 중첩 객체 구조 분해
const response = { data: { user:
const [a, b, c] = [1, 2, 3];
// a=1, b=2, c=3
// 일부만 추출 (건너뛰기)
const [first, , third] = [10, 20, 30];
// first=10, third=30
// 기본값
const [x = 0, y = 0] = [5];
// x=5, y=0
React의 useState가 바로 배열 구조 분해의 대표적인 사용 예입니다. 다음 주에
가장 먼저 만나게 될 패턴입니다.
// React useState — 배열 구조 분해의 핵심 활용
const [count, setCount] = useState(0);
// count = 현재 상태값, setCount = 상태를 변경하는 함수
React 컴포넌트의 props를 받을 때 가장 자주 사용하는 패턴입니다.
// React 컴포넌트 — 파라미터에서 바로 구조 분해
function Card({ title, description, onClick }) {
return (
<div onClick={onClick}>
<h2>{title}</h2>
<p>{description}</p>
</div>
);
}
// 사용할 때
<Card
스프레드(...)는 배열이나 객체를 펼치는 문법이고, Rest는
나머지를 모으는 문법입니다. 같은 ... 기호를 사용하지만
역할이 다릅니다.
// 배열 복사 & 합치기
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const merged = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
// 배열에 새 요소 추가 (원본 변경 없이)
const newArr = [...arr1, 7]; // [1, 2, 3, 7]
React에서 상태를 업데이트할 때, 기존 객체를 직접 수정하지 않고 스프레드로 새 객체를 만드는 패턴을 사용합니다. 이것이 React의 불변 업데이트입니다.
// React 상태 업데이트 — 스프레드로 새 객체 만들기
const [user, setUser] = useState({ name: "철수", age: 25 });
// age만 변경한 새 객체 생성
setUser((prev) => ({ ...prev, age: prev.age + 1 }));
// { name: "철수", age: 26 } — 새 객체, 원본은 그대로
// 배열 상태에 항목 추가
const [items, setItems] = useState(["사과", "배"]);
setItems( prev
// 함수의 나머지 인자 모으기
function sum(...nums) {
return nums.reduce((acc, n) => acc + n, 0);
}
sum(1, 2, 3, 4); // 10
// 구조 분해에서 나머지 모으기
const { id, ...rest } = { id: 1, name: "철수", age: 25 };
// id=1, rest={ name: "철수", age: 25 }
const head tail
Rest 패턴은 React에서 특정 props만 꺼내고 나머지를 하위 컴포넌트에 전달할 때 유용합니다.
// className만 꺼내고, 나머지 props는 button에 전달
function Button({ className, ...rest }) {
return <button className={`btn ${className}`} {...rest} />;
}
API에서 받아온 데이터는 특정 필드가 null이거나 undefined일 수 있습니다.
이때 안전하게 접근하기 위한 두 가지 연산자를 알아봅니다.
?.는 앞의 값이 null 또는 undefined이면
에러 없이 undefined를 반환합니다.
const user = null;
// 기존 방식 — 매번 null 체크를 해야 함
const city = user && user.address && user.address.city;
// 옵셔널 체이닝 — 간결하게
const city2 = user?.address?.city; // undefined (에러 없음)
// 메서드 호출에도 사용 가능
user?.greet?.(); // user가 null이면 undefined, 에러 없음
// 배열 요소 접근에도 사용 가능
const first = arr?.[0]; // arr이 null이면 undefined
??는 왼쪽 값이 null 또는 undefined일 때만 오른쪽 기본값을 반환합니다.
||와의 차이가 중요합니다.
// ?? — null/undefined일 때만 기본값
const name = user?.name ?? "익명";
// || vs ?? 차이 — 이 차이를 반드시 이해하세요
const count1 = 0 || "기본값"; // "기본값" — 0은 falsy이므로
const count2 = 0 ?? "기본값"; // 0 — null/undefined가 아니므로
const text1 = "" || "기본값"; // "기본값" — 빈 문자열은 falsy
const text2 = "" ?? "기본값"; // "" — null/undefined가 아니므로
실무에서 0이나 빈 문자열("")이 유효한 값인 경우가 많습니다. 이때 ||를
쓰면 의도치 않게 기본값으로 대체되므로,
??를 사용하는 것이 안전합니다.
모듈은 파일 단위로 코드를 분리하고, 필요한 것만 import/export하는
시스템입니다. React 프로젝트는 전부 모듈 기반으로 작성됩니다. 하나의
컴포넌트가 하나의 파일이 되는 구조입니다.
// math.js — 유틸 함수는 named export
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
// 다른 파일에서 import — 중괄호 필수
import { add, subtract } from "./math.js";
// 이름 변경도 가능
import { add as sum } from "./math.js";
// Button.jsx — React 컴포넌트는 보통 default export
export default function Button({ label }) {
return <button>{label}</button>;
}
// 다른 파일에서 import — 중괄호 없이, 원하는 이름으로
import Button from "./Button.jsx";
import MyButton from "./Button.jsx"; // 이름 자유롭게 지정 가능
React 프로젝트에서는 일반적으로 컴포넌트는 default export, 유틸 함수나 상수는 named export로 내보냅니다. 실제 React 코드를 열면 이런 구조를 볼 수 있습니다.
// components/UserCard.jsx — 컴포넌트 (default export)
import { formatDate } from "../utils/date";
import styles from "./UserCard.module.css";
export default function UserCard({ name, createdAt }) {
return (
<div className={styles.card}>
<h3>{name}</h3>
<span>{formatDate(createdAt)// utils/date.js — 유틸 함수 (named export)
export function formatDate(date) {
return new Date(date).toLocaleDateString("ko-KR");
}
export function isToday(date) {
return new Date(date).toDateString() === new Date().toDateString();
}
실제 앱에서는 네트워크 요청이 실패하거나, 예상치 못한 데이터가 올 수 있습니다.
try/catch는 이런 에러를 잡아서 앱이 멈추지 않도록 처리하는 문법입니다.
try {
// 에러가 발생할 수 있는 코드
const result = JSON.parse("잘못된 JSON");
} catch (error) {
// 에러 발생 시 실행되는 코드
console.error("파싱 실패:", error.message);
} finally {
// 에러 여부와 관계없이 항상 실행 (선택사항)
console.log("처리 완료");
}
API 호출은 비동기(async)로 이루어지므로, async/await와 try/catch를 함께
사용합니다. 이 패턴은 React에서 데이터를 불러올 때 기본이 됩니다.
async function fetchUser(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP 에러: ${response.status}`);
}
const user = await response.json();
return user
React에서는 useEffect 안에서 API를 호출하고, try/catch로 에러를
처리합니다. 아래 패턴은 다음 주에 React를 배우면서 직접 작성하게 됩니다.
// React useEffect에서의 데이터 fetching — 미리 눈에 익혀두세요
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function loadUser() {
try {
const response = await fetch
아래 코드를 브라우저 콘솔에서 직접 실행해보고 결과를 예측해보세요.
const numbers = [1, 2, 3, 4, 5];
const result = numbers
.filter((n) => n % 2 !== 0)
.map((n) => n * n);
console.log(result);다가오는 스터디 모임 전, 아래 질문에 대해 찾아보고 본인만의 말로 정리한 뒤 댓글로 남겨주세요.