7839

雑草魂エンジニアブログ

【React】Excelファイルの読み込み → json 変換の実装(SheetJS js-xlsx の利用)

今回、Excel ファイルをブラウザで読み込み、json に変換して、API で POST する処理を実装したので、備忘録として残しておく。本記事では、Excel ファイルをブラウザで読み込み、json に変換するまでのコードを紹介する。

SheetJS js-xlsx

今回、Excel ファイルを取り扱うにあたり、「SheetJS js-xlsx」というライブラリを用いた。

github.com

このライブラリを使うことで、ブラウザ上で Excel ファイルを自由に操作することができる。

  • Excel ファイルを読み込み、適切な形に変換する
  • HTML を Excel ファイルにエクスポートする ...etc

本当に便利なライブラリであると思えた。

インストールは以下の通りである。

$ yarn add xlsx

サンプルコード

以下のように、Excel ファイルをブラウザで読み込み、json に変換して表示するまでのサンプルコードとなっている。

f:id:serip39:20200924192432g:plain

import React, { useRef, useState } from 'react'
import XLSX from 'xlsx'
const Component = () => {
  const fileInput = useRef<HTMLInputElement>(null)
  const [fileName, setFileName] = useState('')
  const [excelData, setExcelData] = useState('')

  const handleTriggerReadFile = () => {
    if (fileInput.current) {
      fileInput.current.click()
    }
  }
  const handleReadFile = (fileObj: File) => {
    if (fileObj) {
      setFileName(fileObj.name)
      fileObj.arrayBuffer().then((buffer) => {
        const workbook = XLSX.read(buffer, { type: 'buffer', bookVBA: true })
        const firstSheetName = workbook.SheetNames[0]
        const worksheet = workbook.Sheets[firstSheetName]
        const data = XLSX.utils.sheet_to_json(worksheet)
        setExcelData(JSON.stringify(data))
      })
    }
  }
  return (
    <div style={{ padding: '20px' }}>
      <p style={{ paddingBottom: '20px' }}>Excelファイルをアップロードする</p>
      <button onClick={() => handleTriggerReadFile()}>ファイル選択</button>
      {!!fileName && <span>ファイル名:{fileName}</span>}
      <form style={{ display: 'none' }}>
        <input
          type="file"
          accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
          ref={fileInput}
          onChange={(e) => {
            e.preventDefault()
            handleReadFile(e.currentTarget.files[0])
          }}
        />
      </form>
      {!!excelData && (
        <div
          style={{
            border: 'solid 1px #444',
            marginTop: '10px',
            padding: '10px',
          }}
        >
          {excelData}
        </div>
      )}
    </div>
  )
}
export default Component

通常の form の input ボタンを押して、ファイルを選択してもいいが、button を押すことでファイルを選択できるような実装にしている。

const fileInput = useRef<HTMLInputElement>(null)
const handleTriggerReadFile = () => {
  if (fileInput.current) {
    fileInput.current.click()
  }
}
~省略~
<button onClick={() => handleTriggerReadFile()}>ファイル選択</button>
<form style={{ display: 'none' }}>
  <input
    type="file"
    accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
    ref={fileInput}
    onChange={(e) => {
      e.preventDefault()
      handleReadFile(e.currentTarget.files[0])
    }}
  />
</form>

useRef を用いて input を参照させて、button を Click した際に、参照した input を Click したようにするようにしている。

また、inputに関しては、accept 属性を用いて、Excel ファイルしか選択できないようにしている。

developer.mozilla.org

ファイルが選択されると、onChangeイベントが発火して、以下の処理が実行される。

const handleReadFile = (fileObj: File) => {
  if (fileObj) {
    setFileName(fileObj.name)
    fileObj.arrayBuffer().then((buffer) => {
      // ファイルを読み込む
      const workbook = XLSX.read(buffer, { type: 'buffer', bookVBA: true })
      // 最初のシート名を取得する
      const firstSheetName = workbook.SheetNames[0]
      // 最初のシート名から、ワークシートを取得する
      const worksheet = workbook.Sheets[firstSheetName]
      // シートのデータを JSON として取得する
      const data = XLSX.utils.sheet_to_json(worksheet)
      // JSON 文字列として state に保存する
      setExcelData(JSON.stringify(data))
    })
  }
}

FileReader.readAsArrayBuffer() を用いて実装することもできるが、今回新しいAPIである Blob.arrayBuffer() で実装を行った。Blob.arrayBuffer() はPromiseが返却されるので、処理が非常に書きやすかった。FileReader の場合は、以下のようにイベントハンドラを設定しなくてはいけなかった。

const reader = new FileReader()
reader.onload = (e) => {
  const buffer = e.target.result
  // bufferの処理
}
reader.readAsBinaryString(fileObject)

developer.mozilla.org

Excel ファイルの読み込みに関しては、一部抜粋しているコードの部分にコメントを追記しているので参考にして欲しい。

まとめ

「SheetJS js-xlsx」という便利なライブラリのおかげで、意外に簡単に、Excelファイルの読み込みを実装することができた。本当にライブラリに感謝である。

それでは、ステキな開発ライフを。