Reactのimport/exportが分からない|モジュールの基本を解説

React開発で必須のimport/export文を初心者向けに詳しく解説。デフォルトと名前付きエクスポート、相対パスと絶対パス、実践的な使い方を具体例とともに紹介します。

Learning Next 運営
35 分で読めます

みなさん、Reactのコードを見て困っていませんか?

「importって何?」「exportはどう使うの?」と思ったことはありませんか?

この記事では、Reactのimportとexportをじっくり解説します。 ファイル間でのコード共有がスムーズにできるようになりますよ。

初心者の方でも大丈夫です。 具体例を見ながら、一緒に理解していきましょう!

import/exportって何だろう?

簡単に言うと、ファイル同士でコードをやり取りする仕組みです。

どうしてimport/exportが必要なの?

昔のJavaScriptでは、こんな問題がありました。

// utils.js ファイル
function formatDate(date) {
return date.toLocaleDateString('ja-JP');
}
function calculateAge(birthDate) {
const today = new Date();
const birth = new Date(birthDate);
return today.getFullYear() - birth.getFullYear();
}
// main.js ファイル
console.log(formatDate(new Date())); // エラー!使えない
console.log(calculateAge('1990-01-01')); // エラー!使えない

これでは、他のファイルの関数を使うことができません。 とても不便ですよね。

でも、import/exportがあれば大丈夫です!

// utils.js ファイル
export function formatDate(date) {
return date.toLocaleDateString('ja-JP');
}
export function calculateAge(birthDate) {
const today = new Date();
const birth = new Date(birthDate);
return today.getFullYear() - birth.getFullYear();
}
// main.js ファイル
import { formatDate, calculateAge } from './utils.js';
console.log(formatDate(new Date())); // 正常に動作!
console.log(calculateAge('1990-01-01')); // 正常に動作!

exportでファイルから関数を公開して、importで別のファイルから読み込んでいます。 これで、コードを再利用できるようになります。

モジュールシステムのメリット

import/exportを使うと、こんな良いことがあります。

コードの再利用ができる 同じ関数を複数のファイルで使えます。 一度書けば、どこでも使えるんです。

名前の衝突を防げる 違うファイルで同じ名前の変数があっても問題ありません。 それぞれ独立しているからです。

依存関係が分かりやすい どのファイルがどのコードを使っているか明確になります。 保守がしやすくなりますね。

不要なコードを削除できる 使われていないコードは、ビルド時に自動で削除されます。 アプリが軽くなります。

Reactでよく使うimport/export

Reactでは、こんなパターンをよく見かけます。

// React本体のインポート
import React from 'react';
import ReactDOM from 'react-dom';
// React Hooksのインポート
import { useState, useEffect, useContext } from 'react';
// 外部ライブラリのインポート
import axios from 'axios';
// 自作コンポーネントのインポート
import Header from './components/Header';
import { Button, Modal } from './components/UI';
// CSSファイルのインポート
import './App.css';
// 画像のインポート
import logo from './assets/logo.png';

最初は複雑に見えるかもしれません。 でも心配いりませんよ!

exportの使い方を覚えよう

exportには2つの方法があります。 デフォルトエクスポート名前付きエクスポートです。

デフォルトエクスポート(メインの1つ)

1つのファイルからメインの1つをエクスポートする方法です。

// components/Header.js
import React from 'react';
const Header = ({ title, subtitle }) => {
return (
<header style={{
backgroundColor: '#282c34',
padding: '20px',
color: 'white',
textAlign: 'center'
}}>
<h1>{title}</h1>
{subtitle && <p>{subtitle}</p>}
</header>
);
};
// デフォルトエクスポート
export default Header;

export defaultを使っています。 これで、Headerコンポーネントがメインのエクスポートになります。

別の書き方もできますよ。

// 定義と同時にエクスポート
export default function Header({ title, subtitle }) {
return (
<header>
<h1>{title}</h1>
{subtitle && <p>{subtitle}</p>}
</header>
);
}

どちらも同じ意味です。 お好みで選んでくださいね。

名前付きエクスポート(複数の機能)

1つのファイルから複数の機能をエクスポートする方法です。

// utils/mathUtils.js
// 関数定義と同時にエクスポート
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
export function multiply(a, b) {
return a * b;
}
export function divide(a, b) {
if (b === 0) {
throw new Error('0で割ることはできません');
}
return a / b;
}
// 定数のエクスポート
export const PI = 3.14159;
export const E = 2.71828;

exportを各関数の前に付けています。 これで、複数の関数を一度にエクスポートできます。

まとめてエクスポートする方法もあります。

// 普通に関数を定義
function calculateCircleArea(radius) {
return PI * radius * radius;
}
function calculateCircleCircumference(radius) {
return 2 * PI * radius;
}
// まとめてエクスポート
export { calculateCircleArea, calculateCircleCircumference };

こちらの方が見やすい場合もありますね。

デフォルトと名前付きの組み合わせ

1つのファイルで両方を使うこともできます。

// utils/apiUtils.js
// メインのAPIクライアント(デフォルト)
class ApiClient {
constructor(baseUrl = 'https://api.example.com') {
this.baseUrl = baseUrl;
this.defaultHeaders = {
'Content-Type': 'application/json'
};
}
async request(endpoint, options = {}) {
const url = `${this.baseUrl}${endpoint}`;
const config = {
headers: this.defaultHeaders,
...options
};
try {
const response = await fetch(url, config);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('API request failed:', error);
throw error;
}
}
}
// メインクラスをデフォルトエクスポート
export default ApiClient;
// ヘルパー関数を名前付きエクスポート
export const isValidUrl = (url) => {
try {
new URL(url);
return true;
} catch {
return false;
}
};
export const formatApiError = (error) => {
if (error.response) {
return `API Error: ${error.response.status}`;
} else if (error.request) {
return 'Network Error: ネットワークエラーです';
} else {
return `Error: ${error.message}`;
}
};

ApiClientがメインで、ヘルパー関数は補助的な役割です。 このような使い分けをよく見かけます。

importの使い方をマスターしよう

今度は、エクスポートされたコードを読み込む方法を学びましょう。

デフォルトインポート

デフォルトエクスポートされたものを読み込む方法です。

// App.js
// Reactライブラリのデフォルトインポート
import React from 'react';
// 自作コンポーネントのデフォルトインポート
import Header from './components/Header';
import Footer from './components/Footer';
// 外部ライブラリのデフォルトインポート
import axios from 'axios';
// ユーティリティ関数のデフォルトインポート
import ApiClient from './utils/apiUtils';
const App = () => {
return (
<div className="app">
<Header title="My React App" subtitle="Welcome!" />
<main>
<h2>メインコンテンツ</h2>
</main>
<Footer />
</div>
);
};
export default App;

デフォルトインポートでは、{}を使いません。 シンプルですね。

名前を変えてインポート

デフォルトインポートでは、好きな名前に変更できます。

// 名前を変更してインポート
import MainHeader from './components/Header'; // Header を MainHeader として
import PrimaryButton from './components/Button'; // Button を PrimaryButton として
// 同名のコンポーネントがある場合
import UserHeader from './components/User/Header';
import PageHeader from './components/Page/Header';
const Dashboard = () => {
return (
<div>
<PageHeader title="ダッシュボード" />
<UserHeader user={{ name: 'John Doe' }} />
<PrimaryButton onClick={() => alert('クリック!')}>
ボタン
</PrimaryButton>
</div>
);
};
export default Dashboard;

同じ名前のコンポーネントがある時に便利です。 名前を変えることで区別できます。

名前付きインポート

名前付きエクスポートされたものを読み込む方法です。

// Calculator.js
// React Hooksの名前付きインポート
import { useState, useEffect, useCallback } from 'react';
// 数学ユーティリティの名前付きインポート
import { add, subtract, multiply, divide, PI } from '../utils/mathUtils';
// UIコンポーネントの名前付きインポート
import { Button, Input, Modal } from '../components/UI';
const Calculator = () => {
const [display, setDisplay] = useState('0');
const [operation, setOperation] = useState(null);
const calculate = () => {
const current = parseFloat(display);
const previous = parseFloat(previousValue);
if (operation === '+') {
return add(previous, current);
} else if (operation === '-') {
return subtract(previous, current);
}
// 他の計算処理...
};
return (
<div>
<h2>電卓</h2>
<Input value={display} disabled />
<Button onClick={calculate}>計算</Button>
<p>円周率: {PI}</p>
</div>
);
};
export default Calculator;

名前付きインポートでは、{}を使います。 必要な機能だけを選んでインポートできます。

エイリアス(別名)の使用

名前付きインポートでも名前を変更できます。

// 名前付きインポートでの別名使用
import {
useState as useStateHook,
useEffect as useEffectHook
} from 'react';
// 同名の関数を違う名前でインポート
import {
formatDate as formatDateJP
} from '../utils/dateUtils';
import {
formatDate as formatDateUS
} from '../utils/dateUtilsUS';
// APIヘルパーを分かりやすい名前でインポート
import {
HTTP_STATUS as StatusCodes,
formatApiError as formatError
} from '../utils/apiUtils';
const UserManagement = () => {
const [users, setUsers] = useStateHook([]);
const currentDate = new Date();
const japaneseDate = formatDateJP(currentDate);
const americanDate = formatDateUS(currentDate);
return (
<div>
<h2>ユーザー管理</h2>
<p>日本形式: {japaneseDate}</p>
<p>アメリカ形式: {americanDate}</p>
</div>
);
};
export default UserManagement;

asを使って別名を付けています。 名前の衝突を避けたい時に使います。

全てをまとめてインポート

すべてのエクスポートをまとめて読み込む方法もあります。

// 全ての数学関数をまとめてインポート
import * as MathUtils from '../utils/mathUtils';
// 全てのUIコンポーネントをまとめてインポート
import * as UI from '../components/UI';
const MathDemo = () => {
const [result, setResult] = useState(0);
const performCalculation = () => {
// MathUtilsのメンバーにアクセス
const sum = MathUtils.add(10, 5);
const product = MathUtils.multiply(sum, 2);
setResult(product);
};
return (
<div>
<h2>数学計算デモ</h2>
<p>円周率: {MathUtils.PI}</p>
<p>計算結果: {result}</p>
<UI.Button onClick={performCalculation}>
計算実行
</UI.Button>
<UI.Modal isOpen={true} title="計算完了">
<p>計算が完了しました!</p>
</UI.Modal>
</div>
);
};
export default MathDemo;

*を使って全てを読み込んでいます。 アクセスする時はMathUtils.addのように書きます。

パスの指定方法を理解しよう

ファイルの場所を正しく指定することが大切です。

相対パスの基本

現在のファイルから見た場所を指定する方法です。

// プロジェクト構造の例
/*
src/
├── components/
│ ├── Header/
│ │ └── Header.js
│ └── UI/
│ ├── Button.js
│ └── Modal.js
├── pages/
│ ├── Home/
│ │ └── Home.js
│ └── About/
│ └── About.js
├── utils/
│ ├── mathUtils.js
│ └── dateUtils.js
└── App.js
*/
// pages/Home/Home.js からの相対パス例
// 同じ階層
// import Something from './LocalComponent';
// 一つ上の階層
// import App from '../App';
// 二つ上の階層
// import Header from '../../components/Header/Header';
// 実際の使用例
import React from 'react';
// pages/Home から components/Header へ
import Header from '../../components/Header/Header';
// pages/Home から components/UI へ
import { Button, Modal } from '../../components/UI';
// pages/Home から utils へ
import { add, multiply } from '../../utils/mathUtils';
const Home = () => {
const calculation = multiply(add(5, 3), 2); // 16
return (
<div>
<Header title="ホームページ" />
<main>
<h2>計算結果: {calculation}</h2>
<Button onClick={() => alert('クリック!')}>
ボタン
</Button>
</main>
</div>
);
};
export default Home;

./は現在のフォルダ、../は一つ上のフォルダを意味します。 フォルダ構造をイメージしながら書くとわかりやすいですよ。

絶対パス(srcからのパス)

プロジェクトのsrcフォルダから始まるパスです。

// jsconfig.json または tsconfig.json で設定が必要
/*
{
"compilerOptions": {
"baseUrl": "src"
}
}
*/
// Contact.js
// 絶対パス(src/ から始まる)
import Header from 'components/Header/Header';
import { Button, Input, Modal } from 'components/UI';
import { isValidEmail } from 'utils/validation';
import ApiClient from 'utils/apiUtils';
const Contact = () => {
const [formData, setFormData] = useState({
name: '',
email: '',
message: ''
});
const handleSubmit = async () => {
if (!isValidEmail(formData.email)) {
alert('有効なメールアドレスを入力してください');
return;
}
const apiClient = new ApiClient();
await apiClient.post('/contact', formData);
alert('送信完了!');
};
return (
<div>
<Header title="お問い合わせ" />
<main>
<Input
value={formData.name}
onChange={(e) => setFormData({...formData, name: e.target.value})}
placeholder="お名前"
/>
<Button onClick={handleSubmit}>送信</Button>
</main>
</div>
);
};
export default Contact;

絶対パスの方が分かりやすい場合もあります。 プロジェクトの設定次第ですね。

外部ライブラリ(node_modules)

npmでインストールしたライブラリを読み込む方法です。

// 外部ライブラリのインポート例
// React関連
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
// ルーティング
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
// HTTPクライアント
import axios from 'axios';
// アイコンライブラリ
import { FaHome, FaUser, FaEnvelope } from 'react-icons/fa';
// 日付ライブラリ
import { format, addDays } from 'date-fns';
// UIライブラリ
import { Button, TextField } from '@mui/material';
const ExternalLibraryDemo = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
// axiosを使ったAPI呼び出し
const fetchUsers = async () => {
try {
const response = await axios.get('/api/users');
setUsers(response.data);
} catch (error) {
console.error('エラー:', error);
}
};
fetchUsers();
}, []);
// date-fnsを使った日付処理
const today = new Date();
const formattedDate = format(today, 'yyyy年MM月dd日');
const tomorrow = format(addDays(today, 1), 'yyyy年MM月dd日');
return (
<div>
<h1>
<FaHome /> 外部ライブラリデモ
</h1>
<p>今日: {formattedDate}</p>
<p>明日: {tomorrow}</p>
<Link to="/">
<FaHome /> ホーム
</Link>
<Button variant="contained">
<FaUser /> ボタン
</Button>
</div>
);
};
export default ExternalLibraryDemo;

外部ライブラリは、パッケージ名をそのまま書きます。 とてもシンプルですね。

よくある間違いと解決方法

初心者がつまずきやすいポイントを見てみましょう。

パスの間違い

// よくあるパスの間違い
// ❌ 間違い例
// pages/Home/Home.js から components/Header を呼び出そうとした場合
// 間違い1: 相対パスが間違っている
import Header from './components/Header'; // 現在のフォルダにcomponentsはない
// 間違い2: フォルダ名のtypo
import Header from '../../compnents/Header'; // compnents → components
// 間違い3: 大文字小文字の間違い
import Header from '../../components/header/Header'; // header → Header
// ✅ 正しい例
import Header from '../../components/Header/Header';

パスの間違いはよくあります。 フォルダ構造をしっかり確認しましょう。

import/exportの不一致

// export/importの不一致例
// ❌ 間違い例
// utils/mathUtils.js でのエクスポート
export default function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// 別ファイルでの間違ったインポート
import { add } from './utils/mathUtils'; // エラー!addはデフォルト
import subtract from './utils/mathUtils'; // エラー!subtractは名前付き
// ✅ 正しい例
import add, { subtract } from './utils/mathUtils';
// または分けて書く
import add from './utils/mathUtils';
import { subtract } from './utils/mathUtils';

デフォルトと名前付きを間違えやすいです。 エクスポート方法を確認しましょう。

循環インポート

// 循環インポートの問題
// ❌ 問題のある例
// UserService.js
import { validateUser } from './UserValidator';
export class UserService {
createUser(userData) {
if (validateUser(userData)) {
// ユーザー作成処理
}
}
}
// UserValidator.js
import { UserService } from './UserService'; // 循環インポート!
export function validateUser(userData) {
const userService = new UserService();
// バリデーション処理
}
// ✅ 解決方法
// UserValidator.js(独立させる)
export function validateUser(userData) {
// UserServiceに依存しないバリデーション
return userData.name && userData.email;
}
// UserService.js
import { validateUser } from './UserValidator';
export class UserService {
createUser(userData) {
if (validateUser(userData)) {
// ユーザー作成処理
}
}
}

お互いを参照すると循環インポートになります。 依存関係を整理しましょう。

エラーメッセージの読み方

// よくあるエラーメッセージ
/*
"Module not found: Error: Can't resolve './components/Header'"
→ パスが間違っている
"Attempted import error: 'Header' is not exported"
→ エクスポート名が間違っている
"Cannot resolve module 'react'"
→ パッケージがインストールされていない
*/
// デバッグ方法
console.log('ファイルが読み込まれました'); // ファイル読み込み確認
const Header = ({ title }) => {
console.log('Headerがレンダリングされました'); // レンダリング確認
return <h1>{title}</h1>;
};
console.log('Headerをエクスポートします:', Header); // エクスポート確認
export default Header;

エラーメッセージをよく読むと解決のヒントがあります。 慌てずに確認しましょう。

実践的なベストプラクティス

効率的な開発のためのコツを紹介します。

index.jsを使った整理

// components/UI/index.js
// 複数のコンポーネントをまとめて管理
export { default as Button } from './Button';
export { default as Input } from './Input';
export { default as Modal } from './Modal';
export { default as Loading } from './Loading';
// 使用例
// 一つのパスでまとめてインポート可能
import { Button, Input, Modal, Loading } from 'components/UI';
// index.jsがない場合(比較)
import Button from 'components/UI/Button';
import Input from 'components/UI/Input';
import Modal from 'components/UI/Modal';
import Loading from 'components/UI/Loading';

index.jsを使うと、インポートがスッキリします。 管理も楽になりますよ。

インポートの順序

// App.js
// インポートの推奨順序
// 1. React関連を最初に
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
// 2. 外部ライブラリ
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import axios from 'axios';
// 3. 内部ユーティリティ
import { AuthProvider } from 'contexts/AuthContext';
import { apiClient } from 'utils/api';
// 4. コンポーネント(共通→特定の順)
import { Header, Footer } from 'components/layout';
import { Button, Modal } from 'components/UI';
// 5. ページコンポーネント
import Home from 'pages/Home';
import About from 'pages/About';
// 6. スタイル関連
import 'styles/global.css';
import './App.css';
const App = () => {
return (
<div className="app">
<Header />
<main>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</main>
<Footer />
</div>
);
};
export default App;

順序が決まっていると、コードが読みやすくなります。 チーム開発では特に重要ですね。

まとめ

Reactのimport/exportについて詳しく学習しました。

覚えておきたいポイント

  • import/exportはファイル間でコードを共有する仕組み
  • デフォルトエクスポートは1つのメイン機能用
  • 名前付きエクスポートは複数の機能用
  • パスの指定は相対パス・絶対パス・外部ライブラリの3種類
  • エラーメッセージをよく読んで解決する

実践のコツ

  1. ファイル構造を理解する
  2. エクスポート方法を統一する
  3. インポート順序を決める
  4. index.jsで整理する
  5. エラーを恐れずに試す

最初は複雑に感じるかもしれません。 でも基本的なパターンを覚えれば、自然に使えるようになります。

ぜひこの記事を参考にして、実際にコードを書いて練習してみてください。 きっとReact開発がもっと楽しくなりますよ!

関連記事