Reactのimport/exportが分からない|モジュールの基本を解説
React開発で必須のimport/export文を初心者向けに詳しく解説。デフォルトと名前付きエクスポート、相対パスと絶対パス、実践的な使い方を具体例とともに紹介します。
みなさん、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.jsimport 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: フォルダ名のtypoimport 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.jsimport { validateUser } from './UserValidator';
export class UserService { createUser(userData) { if (validateUser(userData)) { // ユーザー作成処理 } }}
// UserValidator.jsimport { UserService } from './UserService'; // 循環インポート!
export function validateUser(userData) { const userService = new UserService(); // バリデーション処理}
// ✅ 解決方法
// UserValidator.js(独立させる)export function validateUser(userData) { // UserServiceに依存しないバリデーション return userData.name && userData.email;}
// UserService.jsimport { 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種類
- エラーメッセージをよく読んで解決する
実践のコツ
- ファイル構造を理解する
- エクスポート方法を統一する
- インポート順序を決める
- index.jsで整理する
- エラーを恐れずに試す
最初は複雑に感じるかもしれません。 でも基本的なパターンを覚えれば、自然に使えるようになります。
ぜひこの記事を参考にして、実際にコードを書いて練習してみてください。 きっとReact開発がもっと楽しくなりますよ!