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 는 2015년 jQuery 튜토리얼의 JS 랑 거의 안 닮았어. 이 퀘스트에서 쓸 거의 모든 줄이 아래 기능 중 하나는 건드려. 이미 모던 JS 쓰고 있었다면 이 레슨은 승리 랩이야. 한동안 멀리 있었다면 빈 자리들은 숙제로 챙겨 — 뒤 레슨들은 다 가정하고 가.

Destructuring + spread

모든 컴포넌트에서 const { children, className, ...rest } = props 패턴을 본다. rest-spread 는 타입 잡힌 React 컴포넌트가 모르는 props 까지 안쪽 엘리먼트로 전달하는 방식이야 — 하나하나 나열할 필요 없어. 배열 destructuring 도 있어 (const [count, setCount] = useState(0) 가 그거 + 반환된 튜플).

Arrow function + 암묵적 반환

Arrow function 은 자기 this 가 없어 — 둘러싼 scope 의 this 를 잡아. 그래서 React 이벤트 핸들러를 인라인 arrow 로 써도 bind() 없이 동작하는 거야. 암묵적 반환 ((x) => x * 2) 이 .map(item => <Row {...item} />) 패턴의 기반.

Template literal + tagged template

백틱으로 값 보간 + 여러 줄 가능. Tagged template (template literal 로 호출되는 함수) 이 styled-components 나 Track 4 에서 짤 cn 헬퍼들의 동력이야.

Promise, async/await, fetch

모든 data hook, 모든 Server Action, 모든 use() 호출이 Promise 위에 앉아 있어. async function 은 Promise chain 의 sugar. awaitasync 함수 안 (또는 ES module 최상위) 에서만 동작. fetch()Response 로 resolve 되는 Promise 반환 — 그리고 response.json() 도 또 Promise 반환. await (await fetch(url)).json() 같은 더블 await 패턴이 자주 나와서 어느새 안 어색해져.

Optional chaining + nullish coalescing

user?.profile?.name 은 어느 링크에서든 null/undefined 면 short-circuit. value ?? "default"null/undefined 일 때만 fallback (||0, "", false 까지 fallback 발동). 손에 익으면 방어용 if 사다리 안 쓰게 돼.

ES module

Vite 프로젝트의 모든 파일은 ES module. import/export 는 sugar 가 아냐 — 브라우저랑 Node 둘 다 실제로 돌리는 모듈 시스템 자체야. 모던 JS 코드에 require() 보이면 레거시 유지보수 중인 거.

위 중에 낯선 게 있다면: MDN 링크 따라가서 한 번 훑어. 이 퀘스트의 나머지가 이 기능들 가정하는 정도는 체스 책이 나이트 움직임 가정하는 정도야. 멈춰서 보는 건 부끄러운 일이 아냐 — 부끄러운 건 기억나는 척하다가 destructuring 함정 stack trace 디버깅하는 거.

Code

한 컴포넌트 안에 다 들어있는 기능들·tsx
// 이 레슨이 이름 붙인 모던 JS 기능 전부를 작은 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 의 튜플 반환을 destructuring
  const [waves, setWaves] = useState(0);

  // 암묵적 반환 arrow + template literal
  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.body 도 Promise — 그래서 .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

다음 스니펫을 destructuring, optional chaining, nullish coalescing, arrow function 으로 다시 써: function getName(user) { if (user && user.profile && user.profile.name) { return user.profile.name; } else { return 'guest'; } }. 함수 본문은 한 줄을 노려봐.
Hint
const getName = (user) => user?.profile?.name ?? 'guest'; — 모던 JS 기능 셋, 한 줄.

Progress

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

댓글 0

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

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