본문 바로가기
C.W.K.
Stream
Lesson 01 of 07 · published

15분 만의 모던 JS

~15 min · javascript, es2020, refresher, prerequisite

Level 0React 입문자
0 XP0/54 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
JS 입문 강의는 아니야. Vite를 열기 전에 React에서 자주 쓰는 모던 JS 문법이 손에 익어 있는지 빠르게 확인해.

React에서 가장 자주 쓰는 문법

TypeScript로 작성하는 React 19 코드는 오래된 jQuery 튜토리얼의 JavaScript와 생김새가 꽤 달라. 이 퀘스트에서 만날 코드는 아래 문법을 계속 사용해. 이미 익숙하다면 가볍게 복습하고, 낯선 부분이 있다면 여기서 확인해. 뒤 레슨은 이 문법을 안다고 보고 진행할 거야.

구조 분해와 spread

컴포넌트에서는 const { children, className, ...rest } = props 같은 패턴을 자주 만나. 구조 분해로 필요한 값을 꺼내고, rest-spread로 나머지 props를 안쪽 엘리먼트에 한꺼번에 넘기는 방식이야. const [count, setCount] = useState(0)처럼 배열 구조 분해로 반환된 튜플을 받는 패턴도 꼭 익혀 둬.

화살표 함수와 암묵적 반환

화살표 함수는 자체 this를 만들지 않고 바깥 스코프의 this를 사용해. React 이벤트 핸들러를 인라인 화살표 함수로 작성해도 별도의 bind()가 필요 없는 이유야. (x) => x * 2 같은 암묵적 반환은 .map(item => <Row {...item} />)처럼 목록을 JSX로 바꿀 때 자주 써.

템플릿 리터럴과 태그드 템플릿

백틱을 쓰면 문자열 안에 값을 보간하고 여러 줄을 표현할 수 있어. 태그드 템플릿은 템플릿 리터럴을 함수로 처리하는 문법이야. styled-components 같은 도구나 Track 4의 문자열 헬퍼를 읽을 때 이 계열의 문법을 계속 만나게 돼.

프로미스, async/await, fetch

데이터 훅과 서버 액션, use()는 모두 프로미스를 바탕으로 동작해. async/await는 프로미스 체인을 위에서 아래로 읽기 쉽게 표현하는 문법이야. awaitasync 함수 안이나 ES module의 최상위에서 쓸 수 있어. fetch()Response로 이행되는 프로미스를 반환하고, response.json()도 다시 프로미스를 반환해. 그래서 await (await fetch(url)).json()처럼 await가 두 번 등장하는 코드도 흔해.

Optional chaining과 nullish coalescing

user?.profile?.name은 중간 값이 null이나 undefined이면 뒤의 접근을 건너뛰어. value ?? "default"는 값이 null 또는 undefined일 때만 기본값을 써. 반면 ||0, 빈 문자열, false도 거짓으로 취급해. 둘의 차이를 알면 불필요한 방어용 if 연쇄를 줄일 수 있어.

ES module

Vite는 프로젝트 파일을 ES module로 다뤄. importexport는 단순한 문법 설탕이 아니라 브라우저와 Node에서 실제로 동작하는 모듈 시스템이야. 모던 코드에서 require()를 만났다면 레거시 환경을 유지보수하고 있을 가능성이 커.

낯선 문법이 있다면: 연결된 MDN 문서를 한 번 훑고 와. 이 퀘스트는 체스 책이 나이트의 움직임을 전제로 하듯 위 문법을 전제로 진행해. 잠깐 멈춰 확인하는 편이, 아는 척하다가 구조 분해 때문에 생긴 오류를 오래 추적하는 것보다 훨씬 빨라.

Code

한 컴포넌트 안에 다 들어있는 기능들·tsx
// 이 레슨의 모던 JavaScript 기능을 작은 React 컴포넌트 하나에 모았어.
import { useState } from "react";

type MessageProps = {
  user: { profile?: { name?: string } };
  className?: string;
};

export function Greeting({ user, className, ...rest }: MessageProps) {
  // optional chaining + nullish coalescing
  const name = user?.profile?.name ?? "friend";

  // useState가 반환한 튜플을 구조 분해
  const [waves, setWaves] = useState(0);

  // 암묵적 반환 화살표 함수 + 템플릿 리터럴
  const label = `Hello, ${name} — waved ${waves} times`;

  return (
    <div className={className} {...rest}>
      <p>{label}</p>
      <button onClick={() => setWaves((n) => n + 1)}>Wave</button>
    </div>
  );
}
async와 await로 fetch 결과 읽기·ts
type Conversation = { id: string; title: string };

async function loadConversations(): Promise<Conversation[]> {
  const response = await fetch("/api/conversations");
  if (!response.ok) {
    throw new Error(`Failed: ${response.status} ${response.statusText}`);
  }
  // response.json()도 프로미스를 반환해서 await가 한 번 더 붙어.
  const data = (await response.json()) as Conversation[];
  return data;
}

// ES module 안에선 top-level await 동작해.
const conversations = await loadConversations();
console.log(`Loaded ${conversations.length} conversations`);

External links

Exercise

긴 조건문으로 사용자 이름을 찾는 예제를 구조 분해, optional chaining, nullish coalescing, 화살표 함수로 다시 써. 먼저 user?.profile?.name으로 안전하게 이름을 읽고, 값이 없을 때만 guest를 반환하게 만들어.
Hint
const getName = (user) => user?.profile?.name ?? 'guest';처럼 한 줄로 표현할 수 있어. 값이 빈 문자열일 때도 기본값으로 바꿔야 하는지는 별도로 판단해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.