ReactでExcelファイルを作成してダウンロードできるようにする

# はじめに
reactでExcelファイルを作成してダウンロードする方法です。

Projectはcreate-react-appで適当に作成しておきます。
typescriptで行きます
```bash:create-react-app
npx create-react-app make-excel --template typescript
```

# ライブラリの準備
今回はExcelファイルの作成にxlsx
作成したファイルのダウンロードにfile-saver
のそれぞれのライブラリを使用します。
```bash:yarn
yarn add xlsx file-saver
```

file-serverの型情報も追加しておきます
```bash:yarn
yarn add --dev @types/file-saver 
```



# 実装
ExcelDownloadButton というコンポーネントを以下のように作成します。


```react:ExcelDownloadButton
import React from 'react';
import * as XLSX from 'xlsx';
import  saveAs  from 'file-saver';

type Props = {
  fileName:string,
  buttonName:string,
}


const data = [//・・・①
  { name: 'John', age: 30 ,height:160},
  { name: 'Jane', age: 25 ,height:160},
  { name: 'Bob', age: 40 ,height:160}
];

export function ExcelDownloadButton(props:Props) {
  const {fileName, buttonName } = props;

  const handleDownloadClick = () => {
    const worksheet = XLSX.utils.json_to_sheet(data,{header:["name","age","weight","height" ]});//・・・②
    const workbook = XLSX.utils.book_new();//・・・③
    XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');//・・・④
    const excelUnit8Array = XLSX.write(workbook, { type: 'array' });//・・・⑤
    const excelBlob = new Blob([excelUnit8Array],{type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'})//・・・⑥
    saveAs(excelBlob, fileName);//・・・⑦
  };

  return (
    <button onClick={handleDownloadClick}>
      {buttonName}
    </button>
  );
}
```
上記のコードを簡単に解説すると
①Excelファイルに格納するデータを宣言しています。
実際はバックエンドにから受け取ったデータなどになるかと思います。

②ワークシートの作成を行います。
　XLSX.utils.json_to_sheet　に格納するデータをヘッダー情報を指定します
　今回①で宣言した格納予定のデータにweightはありませんがここで指定しておくとweightの空列が生成されます。

③ワークブックを作成しています。

④作成したワークブックにワークシートをシート名を指定して格納します。

⑤ここでワークブックのデータをバイナリデータに変換します。
　optionでarrayを指定しているので形式はUint8Arrayになります。

⑥　⑤で変換したbinaryデータをBlobオブジェクトに変換します。
　typeには'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
　を指定しています。
ここで指定する可能性のあるtypeは以下のどれかになると思います。
↓chatGPTが教えてくれました↓
application/octet-stream : バイナリデータを指定するための汎用的なMIMEタイプです。Excelファイルはバイナリ形式で保存されるため、このMIMEタイプが使用されることがあります。ただし、このMIMEタイプだけではファイルの種類が特定されないため、Webブラウザーが自動的にファイルをダウンロードすることができない場合があります。

application/vnd.ms-excel : これは、古いバージョンのExcelファイルを指定するために使用されます。具体的には、Excel 97-2003ファイル形式を指定するために使用されます。この形式は、.xls拡張子を持つファイルで使用されます。

application/vnd.openxmlformats-officedocument.spreadsheetml.sheet : これは、最新のExcelファイル形式を指定するために使用されます。具体的には、Excel 2007以降のファイル形式を指定するために使用されます。この形式は、.xlsx拡張子を持つファイルで使用されます。

まぁapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetを指定しておけばいいですね


⑦ここでよくあるファイル保存のダイアログが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2916357/89b9e3bc-77e7-5b68-e112-6d2dae58f17f.png)


このcomponentを呼び出しているapp.tsxは以下です
```react:app.tsx
import React from 'react';
import { ExcelDownloadButton } from './ExcelDownloadButton'
import './App.css';


function App() {
  return (

        <ExcelDownloadButton fileName="example.xlsx" buttonName="Download Excel File"/>

  );
}

export default App;
```
気持ちばかりのCSSです
```react:app.css
button{
  height: 100px;
  width: 300px;
  background-color: cadetblue;
  font-size: x-large;
}
```


# ダウンロードしたEXCELファイル
MacのNumbersで開いちゃってますが以下みたいな感じでEXCELファイルが作られます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2916357/b9b81b82-3647-2b8f-1cb3-2bacfece1ac8.png)


②のヘッダー情報の指定のときにweightを指定しているけど①の格納データにはweightをキーに持つデータがないので
weightは空欄の列になってますね！



# まとめ
案外簡単にExcelファイルの操作ができた。


# 参考
xlsxライブラリのnpmページです。

https://www.npmjs.com/package/xlsx

ライセンスはApache-2.0なんで結構自由に使えますね。