Importing and Exporting Components

김동현·2026년 3월 15일

title: 컴포넌트 임포트(Import) 및 엑스포트(Export)하기

컴포넌트의 진짜 마법은 바로 '재사용성'에 있어요. 우리는 다른 컴포넌트들로 구성된 새로운 컴포넌트를 만들 수 있죠. 하지만 컴포넌트를 계속해서 중첩하다 보면, 어느 순간 이것들을 여러 개의 파일로 나누는 게 훨씬 합리적이라는 걸 깨닫게 될 거예요. 이렇게 파일을 나누면 코드를 한눈에 파악하기도 쉽고, 더 많은 곳에서 컴포넌트를 재사용할 수 있답니다.

  • 루트(Root) 컴포넌트 파일이 무엇인지
  • 컴포넌트를 임포트(가져오기)하고 엑스포트(내보내기)하는 방법
  • default(기본) 방식과 named(이름 지정) 방식의 임포트/엑스포트를 언제 사용해야 하는지
  • 하나의 파일에서 여러 개의 컴포넌트를 임포트하고 엑스포트하는 방법
  • 컴포넌트를 여러 파일로 나누는 방법

💡 강사의 팁: 컴포넌트를 파일로 나누기 전에, 위와 같은 컴포넌트 트리 구조를 머릿속으로 그려보는 것이 좋습니다. 최상위에 무엇이 있고, 그 아래에 어떤 부품들이 들어가는지 파악하면 파일을 어떻게 나눌지 감이 잡힐 거예요!

루트 컴포넌트 파일 {/the-root-component-file/}

첫 번째 컴포넌트(Your First Component) 단원에서 여러분은 Profile 컴포넌트와 이를 렌더링하는 Gallery 컴포넌트를 만들어 보았을 거예요.

function Profile() {
  return (
    <img
      src="[https://i.imgur.com/MK3eW3As.jpg](https://i.imgur.com/MK3eW3As.jpg)"
      alt="Katherine Johnson"
    />
  );
}

export default function Gallery() {
  return (
    <section>
      <h1>Amazing scientists</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}
img { margin: 0 10px 10px 0; height: 90px; }

이 컴포넌트들은 현재 루트 컴포넌트 파일(root component file) 안에 살고 있어요. 이 예제에서는 그 파일 이름이 App.js네요. 하지만 여러분이 프로젝트를 어떻게 설정했느냐에 따라 루트 컴포넌트가 다른 파일에 있을 수도 있어요. 예를 들어, Next.js처럼 파일 기반의 라우팅을 사용하는 프레임워크를 쓴다면 페이지마다 루트 컴포넌트가 다르게 존재할 겁니다.

💡 강사의 팁: 일반적으로 Create React App(CRA)이나 Vite 같은 도구로 프로젝트를 시작하면 src/App.js 또는 src/App.jsx가 가장 기본이 되는 루트 컴포넌트 역할을 합니다. 여기가 우리 앱의 '시작점'이라고 생각하시면 돼요.

컴포넌트 엑스포트하고 임포트하기 {/exporting-and-importing-a-component/}

만약 나중에 랜딩 화면을 바꿔서 과학책 목록을 보여주고 싶다면 어떨까요? 아니면 모든 프로필을 다른 곳에 배치하고 싶을 수도 있겠죠? 이럴 때는 GalleryProfile을 루트 컴포넌트 파일에서 밖으로 빼내는 것이 좋습니다. 이렇게 하면 컴포넌트들이 훨씬 모듈화되고, 다른 파일에서도 재사용하기 쉬워져요. 컴포넌트를 옮기는 작업은 다음 세 단계를 거치면 됩니다.

  1. 컴포넌트를 담을 새로운 JS 파일을 만듭니다(Make).
  2. 그 파일에서 함수 컴포넌트를 엑스포트(Export) 합니다. (기본(default) 엑스포트이름 지정(named) 엑스포트 방식을 사용해요).
  3. 컴포넌트를 사용할 파일에서 이를 임포트(Import) 합니다. (기본(default) 임포트 또는 이름 지정(named) 임포트 방식 중 엑스포트할 때 쓴 방식에 맞춰서 가져옵니다).

아래 예제를 보면 ProfileGalleryApp.js에서 빠져나와 Gallery.js라는 새로운 파일로 이동했어요. 이제 App.js를 수정해서 Gallery.js로부터 Gallery를 가져오도록(import) 해봅시다.

// src/App.js
import Gallery from './Gallery.js';

export default function App() {
  return (
    <Gallery />
  );
}
// src/Gallery.js
function Profile() {
  return (
    <img
      src="[https://i.imgur.com/QIrZWGIs.jpg](https://i.imgur.com/QIrZWGIs.jpg)"
      alt="Alan L. Hart"
    />
  );
}

export default function Gallery() {
  return (
    <section>
      <h1>Amazing scientists</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}
img { margin: 0 10px 10px 0; height: 90px; }

이제 이 예제가 어떻게 두 개의 컴포넌트 파일로 쪼개졌는지 눈여겨보세요!

  1. Gallery.js:
    • Profile 컴포넌트를 정의합니다. 이 컴포넌트는 오직 같은 파일 안에서만 쓰이고 외부로 엑스포트 되지는 않아요.
    • Gallery 컴포넌트를 기본 엑스포트(default export) 방식으로 내보냅니다.
  2. App.js:
    • Gallery.js로부터 Gallery기본 임포트(default import) 방식으로 가져옵니다.
    • 최상위 App 컴포넌트를 기본 엑스포트(default export) 방식으로 내보냅니다.

코드를 보다 보면 아래처럼 파일 확장자인 .js를 생략한 파일들을 종종 만나게 될 거예요.

import Gallery from './Gallery';

리액트에서는 './Gallery.js''./Gallery' 둘 다 잘 작동합니다. 하지만 전자(.js를 붙이는 방식)가 네이티브 ES 모듈(native ES Modules)이 동작하는 방식에 좀 더 가깝답니다.

💡 강사의 팁: 최근 개발 트렌드인 Vite 같은 빌드 도구 환경에서는 명시적으로 확장자(.jsx.js)를 적어주는 것을 더 권장하기도 합니다. 명확하게 적어주는 습관을 들이는 것도 좋아요!

Default 엑스포트 vs Named 엑스포트 {/default-vs-named-exports/}

자바스크립트에서 값을 내보내는 방식에는 크게 두 가지가 있어요. 바로 '기본(Default) 엑스포트'와 '이름 지정(Named) 엑스포트'입니다. 지금까지 우리 예제에서는 기본 엑스포트만 사용했죠. 하지만 하나의 파일에서 둘 중 하나만 쓰거나, 두 가지 방식을 모두 사용할 수도 있습니다. 다만, 하나의 파일에는 단 하나의 기본(default) 엑스포트만 있을 수 있어요. 반면에 이름 지정(named) 엑스포트는 원하는 만큼 여러 개를 만들 수 있죠.

Default and named exports

컴포넌트를 어떻게 엑스포트했느냐에 따라 임포트하는 방식도 결정됩니다. 만약 기본 엑스포트로 내보낸 것을 이름 지정 엑스포트 방식으로 가져오려고 하면 에러가 발생할 거예요! 아래 표가 헷갈리지 않게 도와줄 겁니다.

문법(Syntax)엑스포트 구문 (Export statement)임포트 구문 (Import statement)
기본 (Default)export default function Button() {}import Button from './Button.js';
이름 지정 (Named)export function Button() {}import { Button } from './Button.js';

기본(default) 임포트를 작성할 때는 import 뒤에 여러분이 원하는 이름을 아무거나 붙일 수 있어요. 예를 들어, import Banana from './Button.js'라고 적어도 똑같은 기본 엑스포트 값을 가져오게 됩니다. 반면에 이름 지정(named) 임포트를 사용할 때는 양쪽(보내는 쪽과 받는 쪽)의 이름이 정확히 일치해야 해요. 그래서 이름이 지정된(named) 임포트라고 부르는 거랍니다!

개발자들은 보통 파일이 오직 하나의 컴포넌트만 내보낼 때는 '기본 엑스포트'를 사용하고, 여러 개의 컴포넌트나 값을 내보낼 때는 '이름 지정 엑스포트'를 사용하는 경향이 있어요. 여러분이 어떤 코딩 스타일을 선호하든, 컴포넌트 함수와 그것을 담고 있는 파일에는 항상 의미 있는 이름을 지어주세요. export default () => {}처럼 이름이 없는(익명) 컴포넌트는 피하는 게 좋습니다. 나중에 버그를 찾고 디버깅할 때 아주 힘들어지거든요.

💡 강사의 팁: 추가로 알려드리자면, 실무에서는 '이름 지정 엑스포트(Named export)'를 선호하는 팀도 아주 많습니다. 왜냐하면 이름을 바꿀 때 에디터(VS Code 등)가 전체 파일에서 이름을 자동으로 찾아서 바꿔주기 쉽고, 자동 완성(Auto-import)을 할 때도 정확한 이름을 요구하니까 실수를 확 줄여주기 때문이죠.

같은 파일에서 여러 컴포넌트를 엑스포트하고 임포트하기 {/exporting-and-importing-multiple-components-from-the-same-file/}

갤러리 전체가 아니라 딱 하나의 Profile만 화면에 보여주고 싶다면 어떻게 해야 할까요? Profile 컴포넌트 역시 엑스포트할 수 있습니다. 하지만 Gallery.js에는 이미 기본(default) 엑스포트가 자리 잡고 있죠. 그리고 파일 하나에 두 개의 기본 엑스포트를 가질 수는 없어요. 새로운 파일을 만들어서 거기로 빼고 기본 엑스포트를 하거나, 아니면 기존 파일에서 Profile에 대한 이름 지정(named) 엑스포트를 추가할 수 있습니다. 다시 한번 강조할게요. 파일 하나에는 오직 하나의 기본 엑스포트만 가능하지만, 이름 지정 엑스포트는 여러 개가 가능하답니다!

기본 엑스포트와 이름 지정 엑스포트를 섞어 쓰면 혼란스러울 수 있기 때문에, 일부 개발 팀은 오직 한 가지 스타일(전부 기본 엑스포트만 쓰거나, 전부 이름 지정 엑스포트만 쓰는 것)을 고집하기도 하고, 하나의 파일 안에서 이 둘을 섞어 쓰는 걸 피하기도 합니다. 여러분에게 가장 잘 맞는 방식을 선택하세요!

먼저, Gallery.js에서 이름 지정 엑스포트 방식(default 키워드 없이)으로 Profile엑스포트 해볼게요.

export function Profile() {
  // ...
}

그 다음, App.js에서 중괄호({})를 사용하는 이름 지정 임포트 방식으로 Gallery.js로부터 Profile임포트 합니다.

import { Profile } from './Gallery.js';

마지막으로, App 컴포넌트에서 <Profile />렌더링 해줍니다.

export default function App() {
  return <Profile />;
}

이제 Gallery.js에는 두 개의 엑스포트가 존재합니다. 바로 기본 엑스포트인 Gallery와 이름 지정 엑스포트인 Profile이죠. 그리고 App.js는 이 두 가지를 모두 임포트하고 있습니다. 아래 예제에서 <Profile /><Gallery />로 바꿔보기도 하고, 다시 원래대로 돌려보면서 직접 테스트해 보세요!

// src/App.js
import Gallery from './Gallery.js';
import { Profile } from './Gallery.js';

export default function App() {
  return (
    <Profile />
  );
}
// src/Gallery.js
export function Profile() {
  return (
    <img
      src="[https://i.imgur.com/QIrZWGIs.jpg](https://i.imgur.com/QIrZWGIs.jpg)"
      alt="Alan L. Hart"
    />
  );
}

export default function Gallery() {
  return (
    <section>
      <h1>Amazing scientists</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}
img { margin: 0 10px 10px 0; height: 90px; }

이제 여러분은 기본 엑스포트와 이름 지정 엑스포트를 섞어서 멋지게 사용하고 계신 거예요.

  • Gallery.js:
    • Profile 컴포넌트를 Profile이라는 이름의 이름 지정 엑스포트로 내보냅니다.
    • Gallery 컴포넌트를 기본 엑스포트로 내보냅니다.
  • App.js:
    • Gallery.js로부터 ProfileProfile이라는 이름의 이름 지정 임포트로 가져옵니다.
    • Gallery.js로부터 Gallery기본 임포트로 가져옵니다.
    • 최상위 App 컴포넌트를 기본 엑스포트로 내보냅니다.

이번 페이지에서 여러분이 배운 핵심 내용은 다음과 같아요.

  • 루트 컴포넌트 파일이 무엇인지
  • 컴포넌트를 임포트하고 엑스포트하는 방법
  • 언제 어떻게 기본(default) 방식과 이름 지정(named) 방식의 엑스포트/임포트를 사용하는지
  • 하나의 파일에서 여러 개의 컴포넌트를 엑스포트하는 방법

컴포넌트 더 분리해 보기 {/split-the-components-further/}

현재 Gallery.jsProfileGallery를 모두 엑스포트하고 있어서 약간 혼란스러울 수 있어요.

Profile 컴포넌트를 새로운 Profile.js 파일로 완전히 분리해 보세요. 그런 다음, App 컴포넌트가 <Profile /><Gallery />를 연달아 렌더링하도록 수정해 보세요.

Profile을 내보낼 때 기본 엑스포트나 이름 지정 엑스포트 중 아무거나 사용하셔도 됩니다. 하지만 선택한 방식에 맞춰서 App.jsGallery.js 양쪽에서 정확한 임포트 문법을 사용해야 한다는 걸 명심하세요! 헷갈린다면 위에서 살펴본 'Deep Dive(깊게 파고들기)' 섹션의 표를 다시 참고해 보세요.

문법(Syntax)엑스포트 구문 (Export statement)임포트 구문 (Import statement)
기본 (Default)export default function Button() {}import Button from './Button.js';
이름 지정 (Named)export function Button() {}import { Button } from './Button.js';

컴포넌트를 호출하는 곳에 해당 컴포넌트를 임포트하는 것을 잊지 마세요. Gallery 안에서도 Profile을 사용하고 있지 않나요? 😉

// src/App.js
import Gallery from './Gallery.js';
import { Profile } from './Gallery.js';

export default function App() {
  return (
    <div>
      <Profile />
    </div>
  );
}
// src/Gallery.js active
// 저를 Profile.js로 옮겨주세요!
export function Profile() {
  return (
    <img
      src="[https://i.imgur.com/QIrZWGIs.jpg](https://i.imgur.com/QIrZWGIs.jpg)"
      alt="Alan L. Hart"
    />
  );
}

export default function Gallery() {
  return (
    <section>
      <h1>Amazing scientists</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}
// src/Profile.js
img { margin: 0 10px 10px 0; height: 90px; }

한 가지 엑스포트 방식으로 성공하셨다면, 다른 방식으로도 시도해서 동작하게 만들어 보세요!

이름 지정(Named) 엑스포트를 사용한 정답입니다:

// src/App.js
import Gallery from './Gallery.js';
import { Profile } from './Profile.js';

export default function App() {
  return (
    <div>
      <Profile />
      <Gallery />
    </div>
  );
}
// src/Gallery.js
import { Profile } from './Profile.js';

export default function Gallery() {
  return (
    <section>
      <h1>Amazing scientists</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}
// src/Profile.js
export function Profile() {
  return (
    <img
      src="[https://i.imgur.com/QIrZWGIs.jpg](https://i.imgur.com/QIrZWGIs.jpg)"
      alt="Alan L. Hart"
    />
  );
}
img { margin: 0 10px 10px 0; height: 90px; }

기본(Default) 엑스포트를 사용한 정답입니다:

// src/App.js
import Gallery from './Gallery.js';
import Profile from './Profile.js';

export default function App() {
  return (
    <div>
      <Profile />
      <Gallery />
    </div>
  );
}
// src/Gallery.js
import Profile from './Profile.js';

export default function Gallery() {
  return (
    <section>
      <h1>Amazing scientists</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}
// src/Profile.js
export default function Profile() {
  return (
    <img
      src="[https://i.imgur.com/QIrZWGIs.jpg](https://i.imgur.com/QIrZWGIs.jpg)"
      alt="Alan L. Hart"
    />
  );
}
img { margin: 0 10px 10px 0; height: 90px; }

사이트맵 (Sitemap)

모든 문서 페이지 한눈에 보기 (Overview of all docs pages)


추가로 React에 대해 더 깊이 알고 싶은 부분이나 실습 중에 막히는 부분이 있다면 언제든지 말씀해 주세요! 제가 꼼꼼하게 도와드릴게요.

profile
프론트에_가까운_풀스택_개발자

0개의 댓글