React importの基本|モジュールの読み込み方を完全理解

React開発におけるimport文の基本から応用まで詳しく解説。ES6モジュール、デフォルトエクスポート、名前付きエクスポートの使い分けを学べます。

Learning Next 運営
46 分で読めます

あなたも、Reactでimport文を書く時にこんな経験はありませんか?

「どの書き方が正しいの?」「エラーが出るけど理由がわからない...」「デフォルトエクスポートと名前付きエクスポートの違いが分からない...」

React開発では、コンポーネントやライブラリを読み込むためにimport文を頻繁に使います。 でも、様々な書き方があるため、初心者には理解が困難ですよね。

でも大丈夫です!

この記事では、Reactでのimport文の基本から実践的な使い方まで、初心者にもわかりやすく詳しく解説します。 正しいモジュールの読み込み方を理解して、効率的なReact開発を進めていきましょう。

ES6モジュールシステムって何?まずは基本を理解しよう

Reactのimport文は、ES6(ECMAScript 2015)のモジュールシステムに基づいています。

「モジュールシステムって何?」という疑問から、一緒に解決していきましょう。

モジュールってどんなもの?

モジュールには、こんな素晴らしい特徴があります。

  • コードの分割: 機能ごとにファイルを分けて管理
  • 再利用性: 他のファイルから読み込んで使用可能
  • 名前空間の分離: 変数名の衝突を防ぐ
  • 依存関係の明確化: どのファイルがどのモジュールを使用するかが明確

簡単に言うと、コードを整理して、必要な部分だけを読み込む仕組みなんです。

まるで、必要な道具だけを取り出せる工具箱のようなものですね。

エクスポートとインポートの基本を見てみよう

モジュールシステムは、エクスポート(export)とインポート(import)の2つの操作で構成されます。

// math.js - エクスポートする側
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
export const PI = 3.14159;
// Calculator.js - インポートする側
import { add, subtract, PI } from './math.js';
function Calculator() {
const result = add(5, 3);
console.log(`結果: ${result}`);
console.log(`円周率: ${PI}`);
return <div>計算結果: {result}</div>;
}
export default Calculator;

このコードでは、math.jsで関数や定数をエクスポートしています。

exportで公開したものを、importで読み込んで使用できるんです。 Calculator.jsでは必要な機能だけを選んで読み込んでいますね。

デフォルトエクスポートの使い方をマスターしよう

デフォルトエクスポートは、1つのファイルから1つの主要な値をエクスポートする方法です。

「なんでデフォルトエクスポートがあるの?」という疑問も、これを見ればスッキリしますよ。

デフォルトエクスポートの基本形を覚えよう

最も一般的なReactコンポーネントのエクスポート方法です。

// Button.js
import React from 'react';
function Button({ children, onClick, variant = 'primary' }) {
const className = `btn btn-${variant}`;
return (
<button className={className} onClick={onClick}>
{children}
</button>
);
}
// デフォルトエクスポート
export default Button;

この例では、Buttonコンポーネントを作成しています。

export defaultを使うことで、このファイルのメイン機能としてButtonを公開しています。 variantプロパティでボタンの見た目を変更できるんです。

デフォルトインポートの使い方を理解しよう

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

// App.js
import React from 'react';
import Button from './components/Button'; // デフォルトインポート
import Header from './components/Header';
import Footer from './components/Footer';
function App() {
const handleClick = () => {
alert('ボタンがクリックされました!');
};
return (
<div className="app">
<Header />
<main>
<h1>アプリケーション</h1>
<Button onClick={handleClick}>
クリックしてください
</Button>
<Button variant="secondary">
セカンダリボタン
</Button>
</main>
<Footer />
</div>
);
}
export default App;

このコードでは、複数のコンポーネントをインポートしています。

デフォルトインポートでは、import 名前 from 'パス'の形で読み込みます。 名前は自由に決められるので、わかりやすい名前をつけましょう。

デフォルトエクスポートの様々な書き方

デフォルトエクスポートには複数の書き方があります。

// 方法1: 関数定義と同時にエクスポート
export default function UserCard({ user }) {
return (
<div className="user-card">
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
);
}
// 方法2: 関数定義後にエクスポート
function ProductList({ products }) {
return (
<div className="product-list">
{products.map(product => (
<div key={product.id} className="product-item">
<h4>{product.name}</h4>
<p>¥{product.price}</p>
</div>
))}
</div>
);
}
export default ProductList;
// 方法3: 無名関数のエクスポート
export default function({ message }) {
return <div className="alert">{message}</div>;
}
// 方法4: アロー関数のエクスポート
const Navigation = () => {
return (
<nav>
<ul>
<li><a href="/">ホーム</a></li>
<li><a href="/about">について</a></li>
<li><a href="/contact">お問い合わせ</a></li>
</ul>
</nav>
);
};
export default Navigation;

方法1では、関数定義と同時にエクスポートしています。

方法2は、関数を定義してから後でエクスポートする書き方です。 方法3、4はそれぞれ無名関数とアロー関数の例ですね。

どの書き方でも同じように動作しますが、チーム内で統一することが重要です。

名前付きエクスポートを活用しよう

名前付きエクスポートは、1つのファイルから複数の値をエクスポートする方法です。

「複数の機能をまとめて提供したい」そんな時に便利な方法ですよ。

基本的な名前付きエクスポートを見てみよう

複数の関数やコンポーネントを1つのファイルから提供する場合に使用します。

// utils.js
export function formatPrice(price) {
return `¥${price.toLocaleString()}`;
}
export function formatDate(date) {
return new Intl.DateTimeFormat('ja-JP').format(new Date(date));
}
export function validateEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
export const CONSTANTS = {
MAX_ITEMS: 100,
DEFAULT_PAGE_SIZE: 20,
API_BASE_URL: 'https://api.example.com'
};

このコードでは、複数のユーティリティ関数を定義しています。

formatPriceは価格を日本円形式にフォーマットし、formatDateは日付を日本語形式に変換します。 validateEmailはメールアドレスの妥当性をチェックする関数ですね。

複数のコンポーネントもまとめてエクスポート

// UserComponents.js
export function UserProfile({ user }) {
return (
<div className="user-profile">
<img src={user.avatar} alt={user.name} />
<h2>{user.name}</h2>
<p>{user.bio}</p>
</div>
);
}
export function UserList({ users }) {
return (
<div className="user-list">
{users.map(user => (
<UserProfile key={user.id} user={user} />
))}
</div>
);
}
export function UserForm({ onSubmit }) {
const [formData, setFormData] = React.useState({
name: '',
email: '',
bio: ''
});
const handleSubmit = (e) => {
e.preventDefault();
onSubmit(formData);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={formData.name}
onChange={(e) => setFormData({...formData, name: e.target.value})}
placeholder="名前"
/>
<input
type="email"
value={formData.email}
onChange={(e) => setFormData({...formData, email: e.target.value})}
placeholder="メールアドレス"
/>
<textarea
value={formData.bio}
onChange={(e) => setFormData({...formData, bio: e.target.value})}
placeholder="自己紹介"
/>
<button type="submit">送信</button>
</form>
);
}

ここでは、ユーザー関連の3つのコンポーネントをまとめてエクスポートしています。

UserProfileはユーザー情報を表示し、UserListは複数のユーザーをリスト表示します。 UserFormはユーザー情報を入力するフォームコンポーネントです。

名前付きインポートの様々な方法を使いこなそう

名前付きエクスポートされたモジュールを読み込む方法は複数あります。

// App.js
import React, { useState, useEffect } from 'react';
// 個別インポート
import { formatPrice, formatDate, validateEmail } from './utils';
// 複数インポート
import { UserProfile, UserList, UserForm } from './UserComponents';
// 別名でインポート
import { CONSTANTS as AppConstants } from './utils';
// 全てを名前空間としてインポート
import * as Utils from './utils';
import * as UserComponents from './UserComponents';
function App() {
const [users, setUsers] = useState([]);
// 個別インポートした関数の使用
const handleEmailValidation = (email) => {
if (validateEmail(email)) {
console.log('有効なメールアドレスです');
}
};
// 名前空間インポートの使用
const handlePriceFormat = (price) => {
const formatted = Utils.formatPrice(price);
console.log(`価格: ${formatted}`);
};
return (
<div className="app">
<h1>ユーザー管理アプリ</h1>
{/* 個別インポートしたコンポーネントの使用 */}
<UserList users={users} />
{/* 名前空間インポートしたコンポーネントの使用 */}
<UserComponents.UserForm
onSubmit={(userData) => setUsers([...users, userData])}
/>
<p>最大ユーザー数: {AppConstants.MAX_ITEMS}</p>
</div>
);
}
export default App;

このコードでは、様々なインポート方法を紹介しています。

個別インポートでは{ }を使って必要な関数だけを取り出します。 名前空間インポートでは* asを使って、すべての機能を一つの名前空間にまとめているんです。

デフォルトと名前付きエクスポートの混在

1つのファイルでデフォルトエクスポートと名前付きエクスポートを同時に使用することも可能です。

// api.js
const API_BASE_URL = 'https://api.example.com';
// 名前付きエクスポート
export async function fetchUsers() {
const response = await fetch(`${API_BASE_URL}/users`);
return response.json();
}
export async function fetchUserById(id) {
const response = await fetch(`${API_BASE_URL}/users/${id}`);
return response.json();
}
export async function createUser(userData) {
const response = await fetch(`${API_BASE_URL}/users`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(userData)
});
return response.json();
}
// デフォルトエクスポート
class ApiClient {
constructor(baseUrl = API_BASE_URL) {
this.baseUrl = baseUrl;
}
async get(endpoint) {
const response = await fetch(`${this.baseUrl}${endpoint}`);
return response.json();
}
async post(endpoint, data) {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
return response.json();
}
}
export default ApiClient;

このファイルでは、API関連の関数を名前付きエクスポートしています。

同時に、ApiClientクラスをデフォルトエクスポートしています。 これにより、関数とクラスの両方を提供できるんです。

混在エクスポートの使用例

// App.js
import ApiClient, { fetchUsers, createUser } from './api';
function App() {
const [users, setUsers] = useState([]);
useEffect(() => {
// 名前付きインポートした関数の使用
fetchUsers().then(setUsers);
}, []);
const handleCreateUser = async (userData) => {
// 名前付きインポートした関数の使用
await createUser(userData);
// デフォルトインポートしたクラスの使用
const apiClient = new ApiClient();
const updatedUsers = await apiClient.get('/users');
setUsers(updatedUsers);
};
return (
<div>
{/* コンポーネントの内容 */}
</div>
);
}

1行で、デフォルトと名前付きの両方をインポートできます。

必要に応じて使い分けることで、効率的なコードが書けますね。

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

import文では、読み込むファイルのパスを正しく指定することが重要です。

「相対パスと絶対パスの違いって何?」という疑問を解決していきましょう。

相対パスの使い方を覚えよう

同じプロジェクト内のファイルを読み込む場合は、相対パスを使用します。

// ディレクトリ構造
/*
src/
├── App.js
├── components/
│ ├── Header.js
│ ├── Footer.js
│ └── common/
│ ├── Button.js
│ └── Modal.js
├── pages/
│ ├── Home.js
│ ├── About.js
│ └── Contact.js
└── utils/
├── api.js
└── helpers.js
*/
// App.js からの相対パス
import Header from './components/Header'; // 同階層のcomponentsフォルダ
import Footer from './components/Footer';
import Home from './pages/Home'; // 同階層のpagesフォルダ
// Header.js からの相対パス
import Button from './common/Button'; // 同階層のcommonフォルダ
import Modal from './common/Modal';
// Home.js からの相対パス
import Button from '../components/common/Button'; // 上位階層を経由
import { fetchData } from '../utils/api'; // 上位階層のutilsフォルダ
// Button.js からの相対パス
import { formatDate } from '../../utils/helpers'; // 2階層上のutilsフォルダ

相対パスでは、./で同じ階層、../で上位階層を指定します。

../../のように、../を重ねることで、さらに上位の階層にアクセスできるんです。 ファイルの階層関係を意識することが大切ですね。

絶対パスの設定と使用を学ぼう

プロジェクトのルートから始まる絶対パスを使用することで、パスの指定を簡潔にできます。

// jsconfig.json または tsconfig.json での設定
{
"compilerOptions": {
"baseUrl": "src"
}
}
// 絶対パスでのインポート(上記設定後)
// どのファイルからでも同じパスで指定可能
import Header from 'components/Header';
import Button from 'components/common/Button';
import { fetchData } from 'utils/api';
import { formatDate } from 'utils/helpers';
// パスエイリアスの設定例
{
"compilerOptions": {
"baseUrl": "src",
"paths": {
"@components/*": ["components/*"],
"@pages/*": ["pages/*"],
"@utils/*": ["utils/*"],
"@assets/*": ["assets/*"]
}
}
}
// エイリアスを使用したインポート
import Header from '@components/Header';
import Button from '@components/common/Button';
import { fetchData } from '@utils/api';
import logo from '@assets/images/logo.png';

絶対パスを設定すると、どのファイルからでも同じパスで指定できます。

エイリアス(別名)を使うことで、さらに短く読みやすいパスになりますね。 @マークを使うのが一般的な書き方です。

node_modulesからのインポートを理解しよう

外部ライブラリは、node_modulesから直接インポートします。

// 外部ライブラリのインポート
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import axios from 'axios';
import moment from 'moment';
import { Button, Card, Container } from 'react-bootstrap';
// UIライブラリの特定コンポーネントをインポート
import {
AppBar,
Toolbar,
Typography,
IconButton,
Menu,
MenuItem
} from '@mui/material';
// アイコンライブラリからの選択的インポート
import { FaUser, FaEnvelope, FaPhone } from 'react-icons/fa';
import { MdHome, MdSettings, MdLogout } from 'react-icons/md';
function App() {
const [users, setUsers] = useState([]);
useEffect(() => {
// axiosを使用したAPIリクエスト
axios.get('/api/users')
.then(response => setUsers(response.data));
}, []);
return (
<BrowserRouter>
<Container>
<AppBar position="static">
<Toolbar>
<Typography variant="h6">
アプリケーション
</Typography>
<IconButton color="inherit">
<MdSettings />
</IconButton>
</Toolbar>
</AppBar>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/users" element={<UserList users={users} />} />
</Routes>
</Container>
</BrowserRouter>
);
}

外部ライブラリは、パッケージ名で直接インポートできます。

React、React Router、Material-UIなど、様々なライブラリから必要な機能だけを選んで使用できるんです。 アイコンライブラリからは、使用するアイコンだけを個別にインポートするのが効率的ですね。

Reactライブラリのインポートパターンを覚えよう

Reactエコシステムでよく使用されるライブラリのインポートパターンを見てみましょう。

「どのライブラリも使い方が違って混乱する...」そんな悩みを解決しますよ。

React本体とフックの使い方

React本体とよく使用されるフックのインポート方法です。

// React 18以降の推奨方法
import React, {
useState,
useEffect,
useContext,
useReducer,
useMemo,
useCallback,
useRef
} from 'react';
// React DOMのインポート
import { createRoot } from 'react-dom/client';
// Suspenseとlazyのインポート(コード分割用)
import { Suspense, lazy } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
const [count, setCount] = useState(0);
const [data, setData] = useState(null);
useEffect(() => {
// 副作用の処理
}, []);
const memoizedValue = useMemo(() => {
return count * 2;
}, [count]);
return (
<div>
<h1>カウント: {count}</h1>
<button onClick={() => setCount(count + 1)}>
増加
</button>
<Suspense fallback={<div>読み込み中...</div>}>
<LazyComponent />
</Suspense>
</div>
);
}
// React 18のレンダリング
const root = createRoot(document.getElementById('root'));
root.render(<App />);

このコードでは、React 18の新しい書き方を使っています。

useStateで状態管理、useEffectで副作用処理、useMemoでパフォーマンス最適化を行っています。 lazySuspenseを使うことで、コンポーネントの遅延読み込みもできるんです。

ルーティングライブラリの使い方を理解しよう

React Routerの一般的なインポートパターンです。

// React Router v6のインポート
import {
BrowserRouter,
Routes,
Route,
Link,
Navigate,
useNavigate,
useParams,
useLocation,
Outlet
} from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Navigation />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/users" element={<UserLayout />}>
<Route index element={<UserList />} />
<Route path=":id" element={<UserDetail />} />
<Route path="create" element={<UserCreate />} />
</Route>
<Route path="/about" element={<About />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</BrowserRouter>
);
}
function Navigation() {
return (
<nav>
<Link to="/">ホーム</Link>
<Link to="/users">ユーザー</Link>
<Link to="/about">について</Link>
</nav>
);
}
function UserDetail() {
const { id } = useParams();
const navigate = useNavigate();
return (
<div>
<h2>ユーザー詳細: {id}</h2>
<button onClick={() => navigate(-1)}>
戻る
</button>
</div>
);
}
function UserLayout() {
return (
<div>
<h1>ユーザー管理</h1>
<Outlet />
</div>
);
}

React Router v6では、RoutesRouteでルーティングを設定します。

useParamsでURLパラメータを取得し、useNavigateで画面遷移を制御できます。 ネストしたルートではOutletで子コンポーネントを表示するんです。

状態管理ライブラリのパターンを学ぼう

人気の状態管理ライブラリのインポートパターンです。

// Redux Toolkitのインポート
import { configureStore, createSlice } from '@reduxjs/toolkit';
import { Provider, useSelector, useDispatch } from 'react-redux';
// Zustandのインポート
import { create } from 'zustand';
// Jotaiのインポート
import { atom, useAtom } from 'jotai';
// Redux Toolkit の例
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: (state) => {
state.value += 1;
},
decrement: (state) => {
state.value -= 1;
}
}
});
const store = configureStore({
reducer: {
counter: counterSlice.reducer
}
});
function ReduxCounter() {
const count = useSelector(state => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<span>{count}</span>
<button onClick={() => dispatch(counterSlice.actions.increment())}>
+
</button>
<button onClick={() => dispatch(counterSlice.actions.decrement())}>
-
</button>
</div>
);
}

Redux Toolkitでは、createSliceでアクションとリデューサーを一緒に定義します。

useSelectorで状態を取得し、useDispatchでアクションを実行します。 ボイラープレートコードが少なくて、とても書きやすいですね。

ZustandとJotaiの例も見てみよう

// Zustandの例
const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 }))
}));
function ZustandCounter() {
const { count, increment, decrement } = useCounterStore();
return (
<div>
<span>{count}</span>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}
// Jotaiの例
const countAtom = atom(0);
function JotaiCounter() {
const [count, setCount] = useAtom(countAtom);
return (
<div>
<span>{count}</span>
<button onClick={() => setCount(c => c + 1)}>+</button>
<button onClick={() => setCount(c => c - 1)}>-</button>
</div>
);
}

Zustandはシンプルな関数ベースの状態管理です。

Jotaiはアトム(原子)ベースで、より細かい粒度で状態を管理できます。 どちらもとても軽量で使いやすいライブラリですよ。

よくある問題を解決しよう!エラー対処法

React開発でimport文を使用する際によく遭遇する問題と解決方法をまとめました。

「エラーが出たけど、どうすればいいの?」という悩みを一緒に解決していきましょう。

インポートエラーの対処法を覚えよう

よくあるエラー: モジュールが見つからないエラー

// エラー例
Module not found: Can't resolve './Button' in '/src/components'

このエラーが出た時の解決方法をご紹介します。

// ❌ 悪い例(拡張子なし、存在しないパス)
import Button from './Button';
// ✅ 良い例(正しいパスと拡張子)
import Button from './Button.js';
// または
import Button from './components/Button';
// または(ファイルが存在する場合)
import Button from './Button/index.js';

まず、ファイルの場所とパスが正しいかを確認しましょう。

ファイル名や拡張子の間違い、パスの指定ミスがよくある原因です。 特に、大文字小文字の違いにも注意してくださいね。

デフォルトと名前付きエクスポートの混同を避けよう

よくある問題: エクスポート方法とインポート方法が一致しない

// math.js
export function add(a, b) { return a + b; } // 名前付きエクスポート
// ❌ 悪い例(デフォルトインポート)
import add from './math'; // undefined になる
// ✅ 良い例(名前付きインポート)
import { add } from './math';

エクスポートの方法に合わせて、インポートの書き方を変える必要があります。

名前付きエクスポートには{ }を使い、デフォルトエクスポートには使いません。 どちらの方法でエクスポートされているかを確認することが大切ですね。

循環依存の問題を解決しよう

問題: ファイル同士が相互に依存している

// ❌ 悪い例(循環依存)
// A.js
import B from './B';
export default function A() {
return <B />;
}
// B.js
import A from './A';
export default function B() {
return <A />;
}

このような循環依存は避けるべきです。

// ✅ 良い例(共通の親コンポーネントで管理)
// Container.js
import A from './A';
import B from './B';
export default function Container() {
return (
<div>
<A />
<B />
</div>
);
}
// A.js
export default function A() {
return <div>Component A</div>;
}
// B.js
export default function B() {
return <div>Component B</div>;
}

共通の親コンポーネントで両方のコンポーネントを管理します。

こうすることで、AとBが互いに依存することなく、正常に動作するんです。 設計を見直すことで、多くの循環依存は解決できますよ。

動的インポートの活用方法

大きなライブラリやコンポーネントを必要な時だけ読み込む方法です。

import React, { useState, Suspense, lazy } from 'react';
// 動的インポート(コード分割)
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const AdminPanel = lazy(() => import('./AdminPanel'));
// 条件付き動的インポート
const ChartComponent = lazy(() => {
return import('./ChartComponent');
});
function App() {
const [showChart, setShowChart] = useState(false);
const [showAdmin, setShowAdmin] = useState(false);
// 動的にライブラリをインポート
const handleImportLibrary = async () => {
try {
const { default: moment } = await import('moment');
const now = moment().format('YYYY-MM-DD HH:mm:ss');
console.log('現在時刻:', now);
} catch (error) {
console.error('ライブラリの読み込みに失敗:', error);
}
};
return (
<div>
<h1>動的インポートの例</h1>
<button onClick={() => setShowChart(!showChart)}>
チャートを{showChart ? '非表示' : '表示'}
</button>
<button onClick={() => setShowAdmin(!showAdmin)}>
管理画面を{showAdmin ? '非表示' : '表示'}
</button>
<button onClick={handleImportLibrary}>
Momentライブラリを読み込み
</button>
<Suspense fallback={<div>読み込み中...</div>}>
{showChart && <ChartComponent />}
{showAdmin && <AdminPanel />}
<HeavyComponent />
</Suspense>
</div>
);
}
export default App;

lazySuspenseを使うことで、コンポーネントの遅延読み込みができます。

async/awaitを使った動的インポートで、必要な時だけライブラリを読み込むこともできるんです。 これにより、初期ロード時間を短縮できますね。

TypeScriptでの型インポートも覚えよう

TypeScriptを使用している場合の型定義のインポート方法です。

「型の書き方がよくわからない...」という悩みも解決していきましょう。

型のインポート方法を理解しよう

// 型のみをインポート
import type { FC, ReactNode, MouseEvent } from 'react';
import type { User, Product } from './types';
// 値と型を同時にインポート
import React, { useState } from 'react';
import type { SetStateAction } from 'react';
// インターフェースの定義と使用
interface ButtonProps {
children: ReactNode;
onClick: (event: MouseEvent<HTMLButtonElement>) => void;
variant?: 'primary' | 'secondary';
disabled?: boolean;
}
const Button: FC<ButtonProps> = ({
children,
onClick,
variant = 'primary',
disabled = false
}) => {
return (
<button
className={`btn btn-${variant}`}
onClick={onClick}
disabled={disabled}
>
{children}
</button>
);
};
export default Button;
export type { ButtonProps };

import typeを使うことで、型のみをインポートできます。

インターフェースで型を定義し、コンポーネントに適用することで型安全性を保てます。 export typeで型も外部に公開できるんです。

まとめ:import文をマスターして快適な開発を!

お疲れ様でした! Reactでのimport文の使い方について、基本から実践まで詳しく学んできました。

重要なポイントをおさらい

  • デフォルトエクスポート: 1つのファイルから1つの主要な値をエクスポート
  • 名前付きエクスポート: 1つのファイルから複数の値をエクスポート
  • 相対パス: 同じプロジェクト内のファイル間での参照
  • 絶対パス: プロジェクトルートからの参照で可読性を向上
  • 動的インポート: 必要な時だけモジュールを読み込んでパフォーマンス最適化

効果的な使い分けのコツ

使い方を間違えないためのガイドラインはこちらです。

  • コンポーネント: 通常はデフォルトエクスポートを使用
  • ユーティリティ関数: 名前付きエクスポートで複数の関数を提供
  • 設定値・定数: 名前付きエクスポートで意味のある名前を付与
  • 大きなライブラリ: 動的インポートでコード分割
  • 型定義: TypeScriptでは型専用のインポートを活用

学習の進め方

import文の習得は以下の順序で進めることをおすすめします。

  1. 基本的なインポート: デフォルトと名前付きエクスポートの理解
  2. パス指定: 相対パスと絶対パスの適切な使い分け
  3. ライブラリインポート: 外部ライブラリの効率的な読み込み
  4. 動的インポート: パフォーマンス最適化のための遅延読み込み
  5. エラー対処: よくある問題の解決方法の習得

正しいimport文の理解は、効率的で保守性の高いReactアプリケーション開発の基盤となります。

モジュールシステムを適切に活用することで、コードが整理され、チーム開発もスムーズになりますよ。

ぜひ、実際のプロジェクトで様々なインポートパターンを試して、最適な方法を身につけてくださいね!

関連記事