コンポーネントのインポートとエクスポート
コンポーネントの魅力は再利用のしやすさにあります。他のコンポーネントを組み合わせて新しいコンポーネントを作ることができるのです。しかし、コンポーネントのネストが増えてくると、それらを別のファイルに分割したくなってきます。これにより、欲しいファイルを簡単に見つけ出し、より多くの場所でコンポーネントを再利用できるようになります。
このページで学ぶこと
- ルートコンポーネントファイルとは何か
- コンポーネントのインポート・エクスポートの方法
- デフォルトインポート/エクスポートと名前付きインポート/エクスポートの使い分け
- 1 つのファイルから複数のコンポーネントをインポート・エクスポートする方法
- コンポーネントを複数のファイルに分割する方法
ルートコンポーネントファイル
初めてのコンポーネントでは、Profile
コンポーネントと、それをレンダーする Gallery
コンポーネントを作成しました。
Error
Extra 185 of 186 byte(s) found at buffer[1]
これらのコンポーネントは今のところ、ルート (root) コンポーネントファイル(この例では App.js
という名前)に置かれています。セットアップによっては、ルートコンポーネントは別のファイルに存在するかもしれません。Next.js のようなファイルベースのルーティングがあるフレームワークを使っている場合、ルートコンポーネントはページごとに異なるものになります。
コンポーネントのエクスポートとインポート
もし将来ランディングページを変更して科学書のリストを表示したくなった場合はどうでしょうか。あるいはプロフィールを別の場所に表示したくなった場合は? Gallery
や Profile
はルートコンポーネントファイル以外の場所に置きたくなるでしょう。これによりコンポーネントはよりモジュール化され、他のファイルから再利用可能になります。コンポーネントの移動は以下の 3 ステップで行えます。
- コンポーネントを置くための新しい JS ファイルを作成する。
- デフォルトエクスポートあるいは名前付きエクスポートのいずれかを使い、関数コンポーネントをそのファイルからエクスポートする。
- そのコンポーネントを、利用する側のファイルでインポートする。デフォルトエクスポートされたのか名前付きエクスポートされたのかに応じて、対応するインポート手法を使う。
以下の例では、Profile
と Gallery
の両方が、App.js
から Gallery.js
という新しいファイルに移動しています。App.js
を書きかえて、Gallery.js
から Gallery
をインポートするようにできます。
import Gallery from './Gallery.js'; export default function App() { return ( <Gallery /> ); }
Error
Extra 185 of 186 byte(s) found at buffer[1]
元の例がどのようにして 2 つのコンポーネントファイルに分割されたか確認しましょう。
Gallery.js
は:Profile
を定義しているが、これは同一ファイル内でしか使われてないのでエクスポートしていない。- デフォルトエクスポートとして
Gallery
コンポーネントをエクスポートしている。
App.js
は:Gallery.js
からGallery
をデフォルトインポートしている。- ルートの
App
コンポーネントをデフォルトエクスポートしている。
さらに深く知る
JavaScript には値をエクスポートする主な方法が 2 つあります。デフォルトエクスポートと名前付きエクスポートです。これまで、我々の例ではデフォルトエクスポートのみを使ってきました。しかし同じファイルで両方を使うことも、あるいはどちらか片方だけを使うことも可能です。ファイルにはデフォルトエクスポートは 1 つまでしか置けませんが、名前付きエクスポートは好きなだけ置くことができます。
どのようにコンポーネントをエクスポートするかによって、それをどのようにインポートするのかが決まります。デフォルトエクスポートされたものを名前付きエクスポートのようにインポートしようとするとエラーになります! 以下の表が参考になるでしょう。
構文 | Export 文 | Import 文 |
---|---|---|
Default | export default function Button() {} | import Button from './Button.js'; |
Named | export function Button() {} | import { Button } from './Button.js'; |
デフォルトインポートを書く場合、import
の後には好きな名前を書くことができます。例えば import Banana from './Button.js'
と書いたとしても、デフォルトエクスポートされている同じ値を得ることができます。一方で、名前付きエクスポートでは、エクスポート側とインポート側で名前が合致していなければなりません。だからこそ名前付きエクスポートと呼ばれるわけですね。
ファイルがコンポーネントを 1 つだけエクスポートする場合はデフォルトエクスポートが、複数のコンポーネントや値をエクスポートする場合は名前付きエクスポートがよく使われます。どちらのコーディングスタイルが好みの場合でも、コンポーネントやそれが入るファイルには、常に意味の通った名前を付けるようにしてください。export default () => {}
のような名前のないコンポーネントは、デバッグが困難になるため推奨されません。
同じファイルから複数のコンポーネントをエクスポート・インポートする
ギャラリではなく、Profile
を 1 つだけを表示したい場合はどうでしょう。Profile
コンポーネントもエクスポートすればいいのです。しかし、Gallery.js
にはすでにデフォルトエクスポートがあり、デフォルトエクスポートは 2 つ以上存在できません。デフォルトエクスポートを持つ新しいファイルを作成するか、または Profile
用の名前付きエクスポートを追加することができます。1 つのファイルはデフォルトエクスポートを 1 つしか持つことができませんが、名前付きエクスポートはたくさんあっても構いません!
まずは Gallery.js
の Profile
を名前付きでエクスポートします(default
キーワードは付けない)。
export function Profile() {
// ...
}
そして、Gallery.js
の Profile
を App.js
に名前付きでインポートします(中括弧を使う)。
import { Profile } from './Gallery.js';
最後に App
コンポーネントで <Profile />
をレンダーします。
export default function App() {
return <Profile />;
}
これで Gallery.js
には、デフォルトの Gallery
というエクスポートと、名前付きの Profile
というエクスポートの 2 つが含まれるようになりました。App.js
はその両方をインポートしています。この例の <Profile />
を <Gallery />
と書きかえたり、元に戻したりしてみてください。
import Gallery from './Gallery.js'; import { Profile } from './Gallery.js'; export default function App() { return ( <Profile /> ); }
これで、デフォルトと名前付きのエクスポートが混在するようになりました。
Gallery.js
は:Profile
コンポーネントをProfile
という名前付きでエクスポートしている。Gallery
コンポーネントをデフォルトエクスポートしている。
App.js
は:Profile
コンポーネントをGallery.js
からProfile
という名前付きでインポートしている。Gallery
コンポーネントをGallery.js
からデフォルトインポートしている。- ルートの
App
コンポーネントをデフォルトエクスポートしている。
まとめ
このページでは以下のことを学びました。
- ルートコンポーネントファイルとは何か
- コンポーネントのインポート・エクスポートの方法
- デフォルトインポート/エクスポートと名前付きインポート/エクスポートの使い分け
- 1 つのファイルから複数のコンポーネントをインポート・エクスポートする方法
チャレンジ 1/1: コンポーネントファイルをさらに分割する
現在のところ Gallery.js
は Profile
と Gallery
の両方をエクスポートしていますが、これはちょっと混乱の原因になりそうです。
Profile
コンポーネントを Profile.js
という別ファイルに移動し、その後で App
コンポーネントも変更して <Profile />
と <Gallery />
を並べてレンダーするようにしてください。
Profile
をエクスポートするのにデフォルトと名前付きのどちらの手法を使っても構いませんが、App.js
と Gallery.js
の両方で対応するインポート構文を使うようにしましょう! 上記の詳細セクションで挙げたこちらの表を参照しても構いません:
構文 | Export 文 | Import 文 |
---|---|---|
Default | export default function Button() {} | import Button from './Button.js'; |
Named | export function Button() {} | import { Button } from './Button.js'; |
// Move me to Profile.js! export function Profile() { return ( <img src="https://i.imgur.com/QIrZWGIs.jpg" alt="Alan L. Hart" /> ); } export default function Gallery() { return ( <section> <h1>Amazing scientists</h1> <Profile /> <Profile /> <Profile /> </section> ); }
片方のエクスポート構文でうまく動かせたら、もう片方の構文でも動くようにしてみましょう。