【React】モジュール[ES2015] import/export をちゃんと理解する

## モジュール [ES2015]import/export

`export default`って何？？、なんでこの`import`は`import {App} from './src/App.js'`って書くのに、こっちは`import hoge from './src/App.js'`なの？とか不思議に思ったことはありませんか？ （私はあります😒 ）

みんな大好き**React**を書く時に、いつも書いている`import export`をちゃんと理解してちゃんと使うべきなので、メモとして残します。

ES2015で登場したJavaScriptのモジュールの機能により、外部のリソースをインポートして利用できるようになりました。
（念のためですが、モジュールはReactの機能ではありません）

インポートを利用する前提として、別ファイルで利用したい変数や関数などをあらかじめエクスポートしておく必要があります。
モジュールの機能により、便利な変数や関数を再利用できる、モジュールごとにスコープがあることでグローバル変数名に対して上書きしてしまうリスクを回避できるなど、コードの保守性が高まリます。

Reactでは、モジュールのエクスポートとインポート機能を利用してコンポーネント間における変数や関数のやりとりをします。

エクスポートとインポートには**名前付き**と**デフォルト**があります。

### 名前付き`export`と`import`

名前付きエクスポートとインポートについて見ていきましょう。

#### 名前付き`export`

別ファイルからアクセスできるようにするため、名前を付けて作成した変数や関数を名前付きエクスポートします。

```javascript
// 変数 sampleVariable を 宣言
const sampleVariable = "sampleVariable"

// 関数 sampleFunc を 宣言
const sampleFunc = () => console.log('Hello,React!');

// 作成した変数や関数をエクスポートすることで、別ファイルにてインポートできるようになる
export {sampleVariable, sampleFunc}
```

名前付きエクスポートでは、作成した変数や関数の前に`export`を付けることで、作成時の宣言と同時にエクスポートすることもできます。

```javascript
// 変数 sampleVariable を 宣言と同時にエクスポート
export const sampleVariable = "sampleVariable"

// 関数 sampleFunc を 宣言と同時にエクスポート
export const sampleFunc = () => console.log('Hello, Vue.js!');
```

#### 名前付き`import`

次に名前付きエクスポートされた関数や変数を、名前付きインポートします。

`namedExportModule.js`からエクスポートされている変数`sampleVariable`と関数`sampleFunc`をインポートするには次のように記述します。

```JavaScript
import { sampleVariable, sampleFunc } from "./namedExportModule.js";

// 呼び出し
console.log(sampleVariable); // sampleVariable
console.log(sampleFunc); // sampleFunc() {}
console.log(sampleFunc()); // Hello,React!
```

#### 名前付き`export`と`import`のエイリアス

エイリアスの仕組みを利用することで、宣言済の変数や関数に宣言時と異なる名前を指定してインポートすることができます。エイリアスを付けるためには`as`の後に別の名前を指定します。

`namedExportModule.js`からエクスポートされている変数`sampleVariable`を`myVariable`、`sampleFunc`を`myFunc`という名前でインポートするには次のように記述します。

```JavaScript
import {
  sampleVariable as myVariable,
  sampleFunc as myFunc
} from "./namedExportModule.js";

// 呼び出し
console.log(myVariable); // sampleVariable
console.log(myFunc); // sampleFunc() {}
console.log(myFunc()); // Hello,React!
```

名前つきエクスポートをmyModuleオブジェクトとしてまとめてインポートすることもできます。`namedExportModule.js`から、`MyModule`という名前でインポート、`myModule.sampleVariable`、`myModule.sampleFunc`と書いて呼び出します。

```JavaScript
// 名前つきエクスポートをmyModuleオブジェクトとしてまとめてインポート
// import の後の {} は不要
import * as myModule from "./namedExportModule.js";

// 呼び出し
console.log(myModule.sampleVariable); // sampleVariable
console.log(myModule.sampleFunc); // sampleFunc() {}
console.log(myModule.sampleFunc()); // Hello,React!
```

### デフォルト`export`と`import`

デフォルトエクスポートとインポートについて見ていきましょう。

#### デフォルト`export`

デフォルトエクスポートは、モジュールごとに1つだけエクスポートできる特殊なエクスポートです。

次のコード例では、関数の作成と同時にデフォルトエクスポートしています。

```javascript
// defaultエクスポートは、モジュールごとに1つだけエクスポートできる
export default function App(){
  console.log("Hello,React!");
}
```

`export default`は、ファイルごとに1つだけエクスポートするため、インポートする側も何をインポートすればよいか明確です。そのため関数の作成と同時にデフォルトエクスポートする場合、関数名は省略可能です。

```javascript
// defaultエクスポートは、モジュールごとに1つだけエクスポートできる
// 関数名は省略できる
export default function () {
  console.log("Hello,React!");
}
```

複数の変数を同時に作成できる変数については、変数宣言と同時にデフォルトエクスポートすることはできないので注意しましょう。

#### デフォルト`import`

名前付きインポートの場合には`import`の後に`{}`が必要ですが、デフォルトインポートの場合には不要です。

また名前付きエクスポートの場合、指定したモジュールから同じ変数名や関数名を指定してインポートしますが、デフォルトエクスポートの場合、任意の名前をつけてインポートします。

```JavaScript
// デフォルトエクスポートされたモジュールをインポートする場合、import {App} ではなく import App
// App は任意の名前
import App from './defaultExportModule.js'

console.log(App) // App() {}
console.log(App()) // Hello,React!
```

### 再エクスポート

再エクスポートとは、1度インポートしたモジュールを別ファイルが利用できるようにエクスポートし直すことです。`export ... from ...`構文を利用して、インポートした直後にエクスポートできます。

再エクスポートは、複数のモジュールからエクスポートされたものをまとめたモジュールを作るときなどに利用されます。

```JavaScript
// namedExportModule.js から sampleVariable と sampleFunc をインポートした直後に再エクスポート
export { sampleVariable, sampleFunc } from "./namedExportModule.js";

// namedExportModule.js から sampleVariable を myVariable、 sampleFunc を myFunc としてインポートした直後に再エクスポート
export {
  sampleVariable as myVariable,
  sampleFunc as myFunc
} from "./namedExportModule.js";

// 名前つきエクスポートを myModule オブジェクトとしてまとめてインポート
import * as myModule from "./namedExportModule.js";
// myModule オブジェクトを再エクスポート
export {myModule}

// 上記の2行を1行で記述できるようになった[ES2020]
// myModule オブジェクトを再エクスポート
export * as myModule from "./namedExportModule.js";
```

### HTMLファイルからモジュールを呼び出す

HTMLファイルからモジュールを利用しているJavaScriptファイルを呼び出す場合、`type="module"` 属性が必要です。

```html :index.html
<script type="module" src="./modules/importModule.js"></script>
```

JavaScriptの基本をしっかり固めて、ますます楽しいReactライフを!!😍

参考サイト:
- [JavaScript Primer](https://jsprimer.net/basic/module/)
- [MDN Web Dogs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Modules)