🤔

Reactのexport defaultとexportって何がどう違うんや

に公開2

発端の話

業務でReactを触って開発を進めていく中で、以下のようなコードをよく見かけました。

Button.tsx
export default function Button() {
  return <button>押す</button>;
}

一方でこんなコードも見かけました。

Button.tsx
export function Button() {
  return <button>押す</button>;
}

この例は、どちらも「外部からButtonを使えるようにする」ための書き方です。

Reactド初心者の私は、違いはよく知らんけどテストしてみて動いたから一旦ヨシ!
…と実装を進めたら、案の定エラーが出てきて詰まるという状況に陥りました。
(我ながら本当に良くない、、)

  • export defaultはただのexportと何がどう違うんや??
  • 結局どっち使えばええんや??

私と同じように、このあたりがフワッとしてる人がいるだろうな~と思ったので、
忘備録&まとめとして記事に残してみようと思いました。

本題に入る前に

  • ファイル1つ1つがモジュール
  • そのモジュールから外に出すものがexport
  • 逆に他のモジュールが出してくれたものがimport

上記のような仕組み・関係図となっており、
このうちのexportが下記のようにザックリ2種類あって、
そいつらの性格はこう違うよ~というのが今回のテーマです。

  • export default(デフォルトexportとも呼ばれているやつ)
  • export(名前付きexportとかnamed exportとも呼ばれているやつ)

export defaultってなんぞや

このファイルの中で扱ってる商品はコレだけや!
というのがexport defaultのイメージでOKだと思います。

最初の例と同じですが書き方はこちら。

Button.tsx
export default function Button() {
  return <button>押す</button>;
}

これを使う側はこのように書きます。

page.tsx
// Buttonをimportする
import Button from "./components/Button";

// importしたButtonを使う
export default function Page() {
  return (
    <div>
      <Button />
    </div>
  );
}

ポイントは3つ。

  • 1ファイルに複数のexport defaultは書けない
  • importする際は{}なし(後述のexportでは必要です)
  • importする側で 好きな名前をつけられる

例えばこんなこともできます。(ややこしくなるからやらないほうが良さそうだけど)

page.tsx
// 中身はButtonだけど名前はHogeに変更
import Hoge from "./Button";

以下のようにexport defaultを複数書くことはできません。

Button.tsx
export default function Button1() {
  return <button>押す</button>;
}

// export defaultは1ファイル1つのみなのでNG
export default function Button2() {
  return <button>押す</button>;
}

export(名前付きexport)ってなんぞや

このファイルの中にこんな商品とあんな商品があるで!
という商品カタログ的なものが名前付きexportのイメージです。

例えば2つのボタンをexportで用意したら

components/Button.tsx
export function ClickButton() {
  return <button>押す</button>;
}

export function DangerButton() {
  return <button>押さないで</button>;
}

使う側はこうなる

page.tsx
// importは{}が必要
import { ClickButton, DangerButton } from "./components/Button";

// importしたClickButtonとDangerButtonを使う
export default function Page() {
  return (
    <>
      <ClickButton />
      <DangerButton />
    </>
  );
}

ポイントは3つ。

  • 1ファイルに複数exportを書ける(単独exportでもOK)
  • import { ... } from で読み込む
  • 名前が完全一致してないとダメ(大文字小文字も識別されます)
    というところです。

※ 名前の完全一致関連については、以下のようにasを使えば別名を付けることもできます。

page.tsx
// 別名でimportできる
import { ClickButton as Button } from "./components/Button";

export default function Page() {
  return (
    <div>
      <Button />
    </div>
  );
}

結局どういう時にどっちを使えばええんや??

じゃあ結局この2つのexportはどう使い分ければええんや??という話ですが、

  • 1ファイル1コンポーネント派 → export default
  • 複数コンポーネントを1ファイルにまとめたい派 → 名前付きexport

でいいんじゃないかと思いました。

もしくは1プロジェクト内で2つの書き方が混在するとややこしいので、exportのみを使うとか。
ここを上手い具合に運用している方がいらっしゃいましたら、ぜひ教えていただきたいです。

まとめ

export default

  • 1ファイル1つまで
  • import Hoge from "./hoge";
  • 使う側で好きな名前をつけられる

export(名前付きexport)

  • 複数OK
  • import { Hoge, HogeHoge } from "./hoge";
  • 名前はファイル側・使う側で一致させる必要あり(asで別名OK)

Reactでの使い分け

1ファイル1コンポーネント → export default
複数コンポーネント → 名前付きexport

上記のような感覚を持っておけば、
export defaultexportのモヤモヤはだいぶ減るかと思います。

余談(NGケース)

私が今回書き方を間違えて出したエラーメッセージがこちらです。

⨯ Internal error: Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

これはexport defaultexportの使い方を間違えた時に
よく出るエラーですがそれだけではなく、
コンポーネントに不正な値を渡したとき全般で出るエラーとなります。

私が実際にやらかしたのが以下のようなケースでした。

  • importパスを間違えていて、undefinedが来ている
import Button from "./Buton"; // Buttonのスペルミス
  • コンポーネントじゃないオブジェクトをJSXに渡している
const components = { Button };

export function Page() {
  return <components />; // componentsはオブジェクトなのでNG
}

Discussion

junerjuner

1ファイルに複数のexport defaultは書けない

(書き方はいろいろとありますが、)複数の同名の名前つき export が書けないので
単に 変数にできない default と言う予約語の名前の 名前つき export みたいなニュアンスかと
( import() メソッドを使うとよくわかります。

デフォルトをインポート

インポートされたモジュール名前空間オブジェクトを構造分解する場合、default は予約語であるため、default キーの名前を変更する必要があります。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/import#デフォルトをインポート

おもちゃの三洋堂 システム部おもちゃの三洋堂 システム部

同名の名前付きexportは複数書けない → defaultという名前のexportもそのルールに乗っているだけ、確かになるほど…!と納得できました。

自分の中でのexport defaultは「特別なもの」程度のふわっとした理解だったので、
defaultという名前のexportが1個だけ許されている、という見方をしていました、、

コメントいただきありがとうございます!