九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
さてさて、すでにLaravel + React
シリーズの記事を公開しはじめてから1か月ほど経ちました。
個人的な感想としては着実に「Vue 3
よりこっちのほうが好き」になってきているのを感じていて、やりたいこともいろいろ思い浮かぶ今日この頃です。
そして、そんな中思いついたのが・・・・・・
CSV ファイルを読み込み、中身を JSON 化する
機能です。
というのも、私の場合ごくまれに「CSV をオンラインで JSON 化したい」となるんですが「だったら自分で作ってしまおう!」となったわけですね。
そこで❗
今回は「Laravel + React」で「CSV ファイル → JSON 化」する機能を実装してみます。
ぜひ何かの参考になりましたら嬉しいです。😄
「お酒のんで帰ると、
多めにご飯食べちゃいません??
お腹イタイ…」
開発環境: Laravel 9.x、React、Inertia.js、Vite、TailwindCSS
やりたいこと
今回やりたいことは、次のとおりです。
- CSV ファイルを選択すると自動で JSON 化する
- 1行目をキーにした「オブジェクトの配列」に変換できる
- エンコードは、「utf-8」と「shift_jis」に対応する(※)
※ 気持ちとしては、もうそろそろShitf_JIS
はなくなってほしいですね…😂
では、実際に作業をしていきましょう❗
パッケージをインストールする
まずは今回の機能に必要なパッケージ papaparse をインストールします。
npm i papaparse --save
ちなみに、本家のサイトには「People 💗 Papa」と書いていて「いやいや!その表現は誤解されるでしょ…😱」となります(わざとでしょうか😂)
ルートをつくる
次にブラウザから実際にアクセスすることになるルートをセットします。
routes/web.php
use Inertia\Inertia; // 省略 Route::get('csv_parser', fn() => Inertia::render('CsvParser/Index'));
※ 毎回書きますがテストなので1行で書いています。本番は今後の拡張も見据えてコントローラーを使ったほうがいいかもです。
ビューをつくる
では、いきなり今回のメイン部分です。
まずはコードからご覧ください。
resources/js/Pages/CsvParser/Index.jsx
import {useState, useEffect} from 'react'; import Papa from 'papaparse'; export default function Index() { // Config const [isObject, setIsObject] = useState(false); const [encoding, setEncoding] = useState('utf-8'); const encodings = [ 'utf-8', 'shift_jis' ]; // Json parser const [file, setFile] = useState(null); const [json, setJson] = useState(''); const handleFileChange = e => { const files = e.target.files; if(files.length > 0) { setFile(files[0]); } }; useEffect(() => { if(file instanceof File) { Papa.parse(file, { header: isObject, encoding: encoding, skipEmptyLines: true, complete(results) { const csvData = results.data; const jsonText = (csvData.join('') !== '') ? JSON.stringify(csvData) : ''; setJson(jsonText); }, error() { alert('CSVファイルの読み込みに失敗しました。'); } }); } }, [file, isObject, encoding]); return ( <div className="p-5"> <h1 className="mb-5 font-bold">Laravel + React で CSV ファイル → JSON 化する方法</h1> <div className="my-5"> <label className="bg-blue-500 text-white font-bold py-2 px-4 rounded mr-3"> CSV ファイルを選択 <input type="file" className="hidden" accept="text/csv" onChange={handleFileChange} /> </label> <select onChange={e => setEncoding(e.target.value)}> {encodings.map(encoding => ( <option key={encoding} value={encoding}>{encoding}</option> ))} </select> </div> {json && ( <div> <small className="font-bold">取得されたデータ(JSON)</small> <br /> <textarea className="block p-2.5 w-1/2 h-40 text-sm text-gray-900 bg-gray-50 mb-1" value={json} readOnly> </textarea> <div className="px-1"> <label> <input type="checkbox" checked={isObject} onChange={e => setIsObject(e.target.checked)} /> <small>1行目をキーにする</small> </label> </div> </div> ) || ( <div className="bg-gray-100 p-2">CSV データが見つかりません。</div> )} </div> ); }
この中で一番重要なのが、useEffect()
を使っている部分です。
というのも、今回はJSON
化する条件が以下2つあるため、ファイルを読み込んだ時点でPapaparse
にはかけず、選択されたファイルを保持し続ける必要があるためです。
- エンコードは「utf-8 or shift_jis」
- 1行目のキーを使ってオブジェクト化するかどうか
つまり、isObject
かencoding
、もしくはfile
のいずれかに変更があったときにuseEffect()
が起動されることになり、ここではじめてPapaparse
を使ってCSV
をJSON
化しているという流れになっています。
ちなみに、<textarea> 〜 </textarea>
にreadOnly
がついていますが、もしこれが無いと以下のような警告がコンソールに表示されるためです。
Warning: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.
(超意訳:口は悪いけど心優しい荒くれ者 編)
onChange
がないのに、value
プロパティ使っちゃダメに決まってんだろ!だって読み込み専用なんだからな。もしそれでもやりてぇんなら、defaultValue
を使おうぜ。それか、onChange
かreadOnly
をつけな!
ということで今回はJSON
データ部分は変更される必要はないので、readOnly
をつけたとうわけです。
なお、useEffect()
内で以下のようにfile
の中身をチェックしているのは、useEffect()
はページ読み込み時にも実行されるためです。つまり、エラー回避のためにつけているわけですね。
if(file instanceof File) { // 省略 }
作業は以上です。
お疲れ様でした❗
テストしてみる
では実際にテストをしてみましょう。
今回使うCSV
は以下のもので、utf8
とshift_jis
版の2種類を用意しました。
※ 必要でしたら、以下からダウンロードできます。
サンプルCSV(utf-8 & shift_jis)ではVite
を起動してブラウザから「http://******/csv_parser」へアクセスしてください。
すると以下のようなページが表示されます。
では、「CSV ファイルを選択」ボタンをクリックしてutf-8
版のCSV
を選択してみます。
すると・・・・・・
はい❗
CSV
の中身が表示されました。
これは、CSVの中身をそのまま配列化したものですね。
では、次に「1行目をキーにする」にチェックをいれてデータ構成を変更できるか確認してみましょう。
どうなるでしょうか・・・・・・
はい❗
ちょっと文字が小さいのでわかりにくいですが、先ほどは「配列の配列」だったのが、今は「オブジェクトの配列」になりました。
成功です😄
では続いて、この状態でshift_jis
版のCSV
を読み込んでみます。
どうなったでしょうか・・・・・・
はい❗
表示はできましたが、文字化けしています。
これはもちろんutf-8
として読み込まれたからですね。
そこで、エンコードをshift_jis
に変更してみます。
うまくいくでしょうか・・・・・・
はい❗
文字コードを変更した途端、文字化けが解消されました。
すべて成功です😄✨
デモページを用意しました
せっかくなので、デモページをつくりました。
ぜひ以下から体験してみてください。
📝 デモページ
企業様へのご提案
今回見ていただいたように、React + Vite
を使うと、とてもコードが短くても強力な機能を実装することができます。
こうすることで、開発効率やメンテナンスのしやすさが向上するでしょう。
もしそういったご希望をお持ちでしたら、いつでもお気軽にお問い合わせからご連絡ください。
お待ちしております。😄✨
おわりに
ということで今回は、Laravel + React
で「CSV → JSON 変換器」を作ってみました。
正直なところ変換部分はPapaparse
がすべて引き受けてくれるのでReact
の使い方さえわかっていれば逆に「JSON → CSV」へ変換する機能もすぐつくれると思います。(Papaparse
にはunperse()
というメソッドがあります)
ぜひ皆さんも実際に試してみてくださいね。
ではでは〜❗
「なぜか右足の袖だけが
自転車にこすれるので
汚れるんですが…」