Menu

리액트 면접 질문과 답변(React 19)

초급부터 고급까지 약 30개의 리액트 면접 질문을 면접관이 받아들일 짧은 답변과 함께 정리했습니다. 읽는 것보다 보는 것이 쉬운 질문에는 실행 가능한 코드가 있습니다.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

리액트 면접에서 가장 자주 나오는 질문들을 수준별로 묶고, 면접관이 기대하는 방식으로 답했습니다. 짧게, React 19 기준으로 정확하게, 그리고 규칙 뒤의 이유와 함께입니다. 동작을 직접 보는 편이 읽는 것보다 나은 곳에는 실행 가능한 에디터를 두었고, 몇몇 질문은 실행하기 전에 콘솔 출력을 예측해 보게 합니다.

클릭하기 전에 생각해 보세요. 미리보기 아래의 콘솔에는 무엇이 출력되고, 버튼에는 무엇이 표시될까요? 답은 아래 초급 섹션에 있습니다.

초급 질문

React란 무엇인가요?

React는 컴포넌트로 사용자 인터페이스를 만드는 자바스크립트 라이브러리입니다. 현재 데이터에 대한 UI 설명을 반환하는 함수를 작성하면, 그 데이터가 바뀔 때 React가 무엇이 바뀌었는지 알아내서 DOM을 대신 업데이트합니다. 뷰 계층만 담당하며, 라우팅, 데이터 가져오기, 폼은 다른 라이브러리나 Next.js 같은 프레임워크가 맡습니다.

JSX란 무엇인가요?

JSX는 자바스크립트 안에 마크업을 쓰게 해 주는 문법 확장입니다. 컴파일러(Babel, esbuild, SWC)가 각 태그를 React 요소를 만드는 호출로 바꾸므로, <p className="note">{text}</p>는 type: 'p'와 props를 가진 객체가 됩니다. 자바스크립트이기 때문에 class 대신 className을 쓰고, 표현식은 {} 안에 넣으며, 모든 태그를 닫아야 합니다. JSX 페이지에서 규칙을 자세히 다룹니다.

컴포넌트와 요소의 차이는 무엇인가요?

컴포넌트는 props를 받아 UI를 반환하는 함수(또는 클래스)입니다. 요소는 JSX가 만들어 내는 일반 객체로, 무엇을 렌더링할지 설명합니다. <Avatar size={40} />는 type이 Avatar 함수인 요소입니다. React는 컴포넌트를 호출해서 요소를 더 많은 요소로 바꾸며, DOM 태그에 이를 때까지 계속합니다. 요소는 가볍고 불변이며, 컴포넌트를 직접 호출하는 일은 없습니다.

props와 state의 차이는 무엇인가요?

props는 부모가 넘겨주며 컴포넌트 안에서는 읽기 전용입니다. state는 컴포넌트가 소유하고, setter로 시간에 따라 바뀌며, 바뀔 때마다 새 렌더링이 예약됩니다. 흔히 이렇게 말합니다. props는 컴포넌트를 설정하고, state는 컴포넌트의 기억입니다. 같은 값이 부모에서는 state이고 자식에서는 prop일 수 있습니다.

이 페이지의 첫 번째 예제는 무엇을 기록하나요?

logged: 0을 기록하고, 버튼에는 2가 아니라 Count: 1이 표시됩니다. state는 스냅샷입니다. count는 렌더링 전체에서 상수이므로 두 setCount(count + 1) 호출 모두 0 + 1을 계산하고, 새 값은 다음 렌더링에만 존재하므로 로그는 이전 값을 읽습니다. 2를 더하려면 업데이터 형태 setCount((c) => c + 1)를 두 번 쓰세요.

목록에 key가 필요한 이유와, 인덱스가 나쁜 key인 이유는 무엇인가요?

React는 key로 각 목록 항목을 이전 렌더링의 항목과 짝짓습니다. 배열 인덱스를 쓰고 맨 위에 항목을 삽입하면 모든 인덱스가 밀리므로, React는 각 행의 state를 이전 위치에 둔 채 엉뚱한 데이터에 붙입니다.

Ada를 체크한 다음 "Add to top"을 클릭하세요. 체크 표시가 새 첫 번째 행으로 옮겨 갑니다. key={index}를 key={person.id}로 바꾸고 다시 해 보면 체크 표시가 Ada에게 남아 있습니다. 개발 환경에서는 key가 없을 때 React가 경고도 하지만, 미리보기는 프로덕션 빌드처럼 실행되므로 여기서는 그 경고가 보이지 않습니다.

제어 input이란 무엇인가요?

값이 React state에서 오는 input입니다. value를 넘기고 onChange에서 state를 업데이트하므로 React가 유일한 진실의 원천이 되고, 키 입력마다 검증하거나 변환할 수 있습니다. 비제어 input은 자기 값을 DOM에 보관하며, 필요할 때 ref나 폼의 FormData로 읽습니다. UI가 사용자의 입력에 반응해야 할 때는 제어 input이 기본 선택입니다.

상태 끌어올리기란 무엇인가요?

두 컴포넌트가 같은 데이터를 필요로 할 때, state를 가장 가까운 공통 부모로 옮기고 값을 바꾸는 함수와 함께 props로 내려 주는 것입니다. 자식들은 더 이상 각자의 사본을 소유하지 않으므로 서로 어긋날 수 없습니다. 컨텍스트나 스토어를 꺼내기 전에 "형제 컴포넌트는 state를 어떻게 공유하나요"에 대한 표준적인 답입니다.

훅의 규칙은 무엇인가요?

훅은 컴포넌트나 커스텀 훅의 최상위에서만 호출하고, 조건문, 반복문, 중첩 함수 안에서는 절대 호출하지 마세요. 그리고 일반 자바스크립트 함수가 아니라 React 함수에서만 호출하세요. React는 호출 순서로 각 훅을 식별하므로, 그 순서가 렌더링마다 똑같아야 합니다. eslint-plugin-react-hooks 패키지가 두 규칙을 강제합니다.

프래그먼트란 무엇인가요?

프래그먼트는 DOM 노드를 추가하지 않고 여러 요소를 묶습니다. <>...</>를 쓰고, 목록 안에서 key가 필요하면 <Fragment key={id}>를 씁니다. 컴포넌트는 하나의 루트를 반환해야 하는데, 프래그먼트를 쓰면 그 루트가 여러 형제가 될 수 있습니다. 여분의 div가 마크업을 깨뜨리는 테이블이나 flex 레이아웃 안에서 중요합니다.

중급 질문

useEffect의 의존성 배열은 어떻게 동작하나요?

React는 렌더링이 커밋된 뒤(보통 브라우저가 그린 뒤) 이펙트를 실행하고, 그 뒤 배열의 값이 바뀐 렌더링마다(Object.is로 비교) 다시 실행합니다. 배열이 없으면 렌더링마다 실행되고, []이면 첫 렌더링 후 한 번 실행됩니다. 이펙트가 읽는 컴포넌트의 모든 값은 배열에 들어가야 하며, 하나가 빠지면 린터가 알려 줍니다.

이펙트의 클린업은 언제 실행되나요?

이펙트에서 반환한 함수는 이펙트가 새 의존성으로 다시 실행되기 전에, 그리고 컴포넌트가 언마운트될 때 한 번 실행됩니다. 이펙트가 설정한 것을 되돌리는 곳입니다. 타이머 정리, 리스너 제거, 연결 닫기 같은 것들입니다.

"Switch room"을 클릭하고 콘솔을 보세요. 이전 방의 클린업이 먼저 실행되고, 그다음 이펙트가 새 방에 연결합니다. "Hide chat"은 클린업만 실행합니다. 개발 환경에서는 StrictMode가 클린업이 동작하는지 확인하기 위해 마운트 시 연결, 연결 해제, 연결을 한 번 더 추가합니다. 미리보기는 프로덕션 빌드처럼 실행되므로 실제 순서만 보입니다.

setInterval 안에서 state가 낡아 보이는 이유는 무엇인가요?

interval 콜백은 자신을 만든 렌더링의 count를 가둔 클로저입니다. 의존성 배열이 비어 있으면 이펙트가 다시 실행되지 않으므로, 콜백은 첫 번째 count를 영원히 읽습니다.

broken은 틱마다 0 + 1을 계산하므로 1에 도달하고 멈춥니다. fixed는 업데이터 함수가 최신 값을 받으므로 계속 셉니다. broken을 의존성 배열에 추가해도 동작하지만, 매초 interval을 정리하고 다시 만드는 비용이 듭니다.

배칭(batching)이란 무엇인가요?

React는 여러 state 업데이트를 렌더링 한 번으로 묶습니다. React 18부터는 이벤트 핸들러, timeout, 프로미스, 네이티브 이벤트 리스너 등 모든 곳에 적용됩니다. 업데이트 하나 직후에 DOM이 바로 업데이트되어야 한다면 react-dom의 flushSync로 빠져나올 수 있지만, 그럴 일은 거의 없습니다.

클릭하면 렌더링 세 번이 아니라 render 1 1 1 한 번이 기록됩니다. React 18 이전에는 timeout 안의 state 업데이트 세 개가 렌더링 세 번을 뜻했습니다.

이것은 무엇을 기록하나요? (이펙트 순서)

코드를 읽고, 콘솔을 보기 전에 콘솔이 출력할 네 줄을 순서대로 적어 보세요.

렌더링은 위에서 아래로 진행됩니다. render App, 그다음 render Child입니다. 이펙트는 트리 전체가 커밋된 뒤 아래에서 위로 실행됩니다. effect Child, 그다음 effect App입니다. 부모의 이펙트는 자식의 이펙트가 이미 실행되었다고 믿을 수 있습니다.

useMemo와 useCallback의 차이는 무엇인가요?

useMemo(() => compute(a, b), [a, b])는 계산 결과를 캐시합니다. useCallback(fn, [deps])는 함수 자체를 캐시하므로 useMemo(() => fn, [deps])와 같습니다. 둘 다 memo 자식이나 다른 훅의 의존성 배열처럼 아래쪽에서 참조로 비교하는 무언가가 있을 때만 도움이 됩니다. React Compiler 1.0(2025년 10월)부터는 빌드 단계에서 이 메모이제이션을 자동으로 추가할 수 있지만, 직접 쓰는 메모이제이션도 여전히 동작하며 대부분의 코드베이스에서 여전히 보게 됩니다.

React.memo는 무엇을 하며, 왜 useCallback이 자주 필요한가요?

memo(Component)는 props가 지난번과 같으면(하나씩 Object.is로 비교) 컴포넌트의 리렌더링을 건너뜁니다. 부모에 인라인으로 쓴 함수는 렌더링마다 새 함수이므로 바뀐 prop으로 취급되어 memo를 무력화합니다. useCallback은 렌더링 사이에 같은 함수를 유지합니다.

콘솔을 지우고 "Re-render parent"를 클릭하세요. render inline handler만 나타납니다. 다른 자식은 같은 함수를 받아서 건너뛰었습니다. Button을 감싼 memo(...)를 지우면 클릭할 때마다 둘 다 로그를 남기며, useCallback만으로는 아무것도 하지 못한다는 것을 보여 줍니다.

컨텍스트란 무엇이며, 비용은 무엇인가요?

컨텍스트는 props로 일일이 넘기지 않고 Provider 아래의 모든 컴포넌트에 값을 전달합니다. createContext, 그다음 React 19에서는 <ThemeContext value={theme}>(또는 <ThemeContext.Provider>), 그리고 읽을 때는 useContext(ThemeContext)입니다. 비용은 값이 바뀌면 그 컨텍스트를 읽는 모든 컴포넌트가 다시 렌더링되고, memo로도 막을 수 없다는 것입니다. 관련 없는 값은 별도의 컨텍스트로 나누고, 객체 값은 useMemo로 감싸고, 빠르게 바뀌는 state는 앱 전체 컨텍스트에서 빼서 비용을 낮게 유지하세요. useContext를 참고하세요.

ref란 무엇이며, 언제 state 대신 쓰나요?

useRef(initial)은 current 속성이 렌더링 사이에 유지되는 객체를 반환하며, 그것을 바꿔도 렌더링이 일어나지 않습니다. 화면이 의존하지 않는 값(타이머 id, 이전 값, 플래그)과 DOM 접근(<input ref={inputRef}> 후 inputRef.current.focus())에 ref를 쓰세요. 값이 화면에 보인다면 state에 속합니다.

가상 DOM이란 무엇이며, 재조정이란 무엇인가요?

렌더링마다 React는 요소의 새 트리를 만들어 이전 트리와 비교합니다. 이 비교가 재조정입니다. 요소의 타입이 바뀌었다면(div가 section이 되거나 ProfileA가 ProfileB가 되면) React는 그 하위 트리와 state를 파괴하고 새로 만듭니다. 타입이 같다면 DOM 노드를 유지하고 바뀐 props를 업데이트하며, 목록의 자식들은 key로 짝짓습니다. "가상 DOM"은 메모리 안의 그 트리를 흔히 부르는 이름이며, 속도는 트리 자체가 빠르기 때문이 아니라 바뀐 것만 건드리기 때문에 나옵니다.

커스텀 훅이란 무엇인가요?

이름이 use로 시작하고 다른 훅을 호출하는 함수로, 컴포넌트 사이에서 상태 로직을 재사용하게 해 줍니다. useOnlineStatus, useLocalStorage, useDebouncedValue 같은 것들입니다. 그것을 호출하는 각 컴포넌트는 자기만의 독립적인 state를 받습니다. 커스텀 훅은 데이터가 아니라 로직을 공유합니다. 커스텀 훅을 참고하세요.

StrictMode는 무엇을 하나요?

<StrictMode>는 개발 환경에서만 추가 검사를 켭니다. 순수하지 않은 렌더링을 드러내기 위해 컴포넌트를 두 번 렌더링하고, 빠진 클린업을 드러내기 위해 마운트 시 이펙트의 setup, cleanup, setup을 한 번 실행하며, ref 콜백도 똑같이 하고, 지원 중단된 API를 경고합니다. 프로덕션 빌드에서는 이 중 아무것도 일어나지 않으므로, 개발 환경에서 콘솔 로그가 두 번 나오는 것은 예상된 일이지 버그가 아닙니다.

고급 질문

이것은 무엇을 기록하나요? (렌더링, 레이아웃 이펙트, 이펙트)

예측 하나 더입니다. 로그 세 개, 렌더링의 서로 다른 세 순간입니다.

useEffect가 먼저 쓰여 있어도 순서는 렌더링, 그다음 useLayoutEffect, 그다음 useEffect입니다. 레이아웃 이펙트는 React가 DOM을 업데이트한 뒤 브라우저가 그리기 전에 실행되므로 요소 측정에 적합합니다. 일반 이펙트는 그 뒤, 보통 그린 다음에 실행되며 기본 선택이어야 합니다.

에러 바운더리란 무엇인가요?

자식을 렌더링하는 중에 던진 오류를 잡아서, 앱 전체를 언마운트하는 대신 대체 UI를 보여 주는 클래스 컴포넌트입니다. static getDerivedStateFromError(대체 UI로 전환)가 필요하고, 보통 componentDidCatch(로깅)도 씁니다. 여전히 대응하는 훅이 없으므로, 함수 컴포넌트 코드베이스에서는 팀이 클래스 하나를 작성하거나 react-error-boundary 패키지를 씁니다.

"Break it"을 클릭하세요. 대체 UI가 바운더리의 자식만 대체하고, 버튼은 남아 있으며, React는 잡힌 오류를 여전히 콘솔에 보고합니다. 바운더리는 이벤트 핸들러, setTimeout 같은 비동기 코드, 바운더리 자신의 오류는 잡지 않습니다. 그런 경우에는 try/catch를 쓰고 state를 설정합니다.

포털이란 무엇인가요?

react-dom의 createPortal(children, domNode)은 자식을 다른 DOM 노드, 보통 document.body에 렌더링하면서 React 트리에서는 같은 자리에 둡니다. 모달, 툴팁, 토스트가 부모의 overflow: hidden이나 쌓임 맥락에서 벗어나기 위해 씁니다. 포털을 거쳐도 컨텍스트는 동작하고, 이벤트는 React 트리를 따라 버블링되므로 DOM 노드가 다른 곳에 있어도 포털 안의 클릭은 부모의 onClick에 도달합니다. 포털을 참고하세요.

Suspense와 lazy란 무엇인가요?

lazy(() => import('./Chart'))는 컴포넌트가 처음 렌더링될 때 그 코드를 불러오므로 번들을 나눕니다. <Suspense fallback={<Spinner />}>는 안의 무언가가 아직 로딩 중인 동안 대체 UI를 보여 줍니다. lazy 코드, 또는 use(promise)나 Suspense를 지원하는 프레임워크로 읽는 데이터입니다. 경계를 어디에 두느냐가 페이지의 어떤 부분이 함께 기다릴지 결정합니다.

import { lazy, Suspense } from 'react';

const Chart = lazy(() => import('./Chart.jsx'));

export default function Dashboard() {
    return (
        <Suspense fallback={<p>Loading chart...</p>}>
            <Chart />
        </Suspense>
    );
}

useTransition은 무엇을 하나요?

state 업데이트를 긴급하지 않은 것으로 표시합니다. const [isPending, startTransition] = useTransition()과 startTransition(() => setTab('posts'))를 쓰면 React가 현재 화면의 반응성을 유지하고, 키 입력처럼 더 긴급한 업데이트가 오면 느린 렌더링을 중단할 수 있습니다. isPending은 힌트를 보여 줄 때를 알려 줍니다. React 19에서는 넘기는 함수가 async일 수 있으며, React는 이것을 액션이라고 부릅니다. 텍스트 input 자체의 값을 업데이트하는 데는 쓰지 마세요. 그 업데이트는 긴급해야 합니다.

React 서버 컴포넌트란 무엇인가요?

서버에서만(또는 빌드 시점에) 실행되고, 코드가 아니라 렌더링된 결과를 브라우저로 보내는 컴포넌트입니다. async일 수 있고 데이터베이스나 파일 시스템을 직접 읽을 수 있지만, state, 이펙트, 브라우저 API는 쓸 수 없습니다. 'use client'로 표시한 파일은 상호작용 컴포넌트가 사는 클라이언트 경계를 시작하고, 'use server'는 클라이언트 코드가 호출할 수 있는 서버 함수를 표시합니다. App Router를 쓰는 Next.js 같은 프레임워크를 통해 사용하며, 일반 Vite 앱에는 그것을 실행할 서버가 없습니다.

React 19에서 무엇이 바뀌었나요?

  • 액션: 대기 상태를 대신 처리해 주는, 트랜지션 안의 async 함수입니다. <form action={fn}>은 폼의 FormData와 함께 fn을 호출합니다.
  • 새 훅: 폼의 결과와 대기 상태를 위한 useActionState, 낙관적 UI를 위한 useOptimistic, 그리고 react-dom의 useFormStatus.
  • use: 프로미스(완료될 때까지 일시 중단)나 컨텍스트를 읽으며, 다른 훅과 달리 조건문 안에서 호출할 수 있습니다.
  • prop으로서의 ref: 함수 컴포넌트가 다른 prop처럼 ref를 받으므로 새 코드에는 forwardRef가 더 이상 필요 없습니다. ref 콜백은 클린업 함수를 반환할 수 있습니다.
  • Provider로서의 <Context>, 그리고 문서 head로 끌어올려지는 <title>과 <meta> 태그.
  • 제거된 것: ReactDOM.render, 문자열 ref, 레거시 컨텍스트, 함수 컴포넌트의 defaultProps(매개변수 기본값을 쓰세요).
// React 19: ref is a normal prop
function TextInput({ ref, ...props }) {
    return <input ref={ref} {...props} />;
}

React 19 페이지에 각각의 실행 가능한 예제가 있습니다.

React 컴포넌트는 어떻게 테스트하나요?

React Testing Library와 Vitest나 Jest 같은 러너로 테스트합니다. 컴포넌트를 렌더링하고, 사용자가 하듯이(역할, 라벨, 텍스트로) 요소를 찾고, user-event로 상호작용한 뒤, 내부 state가 아니라 눈에 보이는 것을 검증합니다. 그래야 리팩터링을 거쳐도 테스트가 유효합니다.

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Counter from './Counter';

test('counts clicks', async () => {
    const user = userEvent.setup();
    render(<Counter />);
    await user.click(screen.getByRole('button', { name: /clicked 0 times/i }));
    expect(screen.getByRole('button')).toHaveTextContent('Clicked 1 times');
});

toHaveTextContent는 @testing-library/jest-dom에서 옵니다. 여러 페이지에 걸친 전체 흐름에는 팀이 그 위에 Playwright나 Cypress를 더합니다.

성능 문제는 어떻게 찾고 고치나요?

먼저 측정하세요. React DevTools의 Profiler 탭을 열고, 느린 상호작용을 기록하고, 플레임 차트를 읽으세요. 어떤 컴포넌트가 렌더링되었는지, 각각 얼마나 걸렸는지, ("record why each component rendered" 설정을 켜면) 왜 렌더링되었는지 보여 줍니다. 시도할 순서대로의 흔한 해결책은 다음과 같습니다. state를 아래로 옮겨서 의존하는 컴포넌트를 줄이고, 느린 하위 트리를 children으로 넘기고, 비용이 큰 부분을 memo, useMemo, useCallback으로 메모이제이션하고, 긴 목록을 가상화하고, 무거운 업데이트를 useTransition이나 useDeferredValue로 미루세요. 프로덕션이나 프로파일링 빌드에서 측정하세요. 개발 빌드는 더 느리고 렌더링 시간을 과장합니다.

컴포넌트는 왜 순수해야 하나요?

같은 props, state, 컨텍스트가 주어지면 컴포넌트는 같은 JSX를 반환하고, 렌더링하는 동안 자기 바깥의 아무것도 바꾸지 않아야 합니다. React는 컴포넌트를 여러 번, 순서와 다르게 렌더링하거나 렌더링을 버릴 수 있으므로(트랜지션, Suspense, StrictMode), 변수 변경이나 요청 전송 같은 본문 안의 부수 효과는 예측할 수 없는 횟수만큼 실행됩니다. 부수 효과는 우선 이벤트 핸들러에, 이벤트가 원인이 아니라면 이펙트에 속합니다.

이펙트를 쓰지 말아야 할 때는 언제인가요?

값을 렌더링 중에 계산할 수 있을 때(필터링된 목록, 전체 이름, 합계), 작업이 사용자 행동 때문에 일어날 때(이벤트 핸들러에 두세요), 그리고 prop이 바뀔 때 state를 초기화하고 싶을 때(key를 쓰세요)입니다. 이펙트는 네트워크 연결, 브라우저 API, 서드파티 위젯처럼 React 바깥의 것과 동기화하기 위한 것입니다. state를 설정하는 이펙트의 연쇄는 추가 렌더링과 버그의 흔한 원인입니다.

자주 묻는 질문

React란 무엇인가요?

React는 컴포넌트로 사용자 인터페이스를 만드는 자바스크립트 라이브러리입니다. 현재 데이터에 맞게 화면이 어떻게 보여야 하는지 설명하면, 그 데이터가 바뀔 때 React가 실제 DOM을 업데이트합니다.

state와 props의 차이는 무엇인가요?

props는 부모가 컴포넌트에 넘기는 입력이며, 컴포넌트는 이를 읽기 전용으로 다룹니다. state는 컴포넌트가 소유하고 setter로 시간에 따라 바꾸는 데이터이며, 바뀌면 React가 컴포넌트를 다시 렌더링합니다.

React에서 훅이란 무엇인가요?

훅은 이름이 use로 시작하는 함수로, 함수 컴포넌트가 React 기능을 쓸 수 있게 해 줍니다. state에는 useState, 부수 효과에는 useEffect, 컨텍스트에는 useContext, 렌더링을 일으키지 않는 값에는 useRef 등을 씁니다.

가상 DOM이란 무엇인가요?

React가 메모리에 가지고 있는 UI 설명을 부르는 이름입니다. 렌더링마다 React는 새 설명을 만들어 이전 것과 비교하고, 차이만 실제 DOM에 적용합니다. 그 비교를 재조정(reconciliation)이라고 합니다.

React 목록에서 key가 중요한 이유는 무엇인가요?

key는 렌더링 사이에 목록의 어느 항목이 어느 항목인지 React에 알려 줍니다. id 같은 안정적인 key가 있으면 항목이 추가, 제거, 재정렬될 때 React가 각 항목의 state와 DOM 노드를 올바른 데이터에 붙여 둡니다. 배열 인덱스를 쓰면 순서가 바뀔 때 이것이 깨집니다.

JSX란 무엇인가요?

JSX는 자바스크립트 안에 HTML 같은 마크업을 쓰게 해 주는 문법 확장입니다. 컴파일러가 각 태그를 React 요소를 만드는 함수 호출로 바꾸므로, <h1>Hi</h1>은 h1을 설명하는 일반 객체가 됩니다.

Coddy 프로그래밍 언어 일러스트

Coddy로 코딩 배우기

시작하기