
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、すでに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()
というメソッドがあります)
ぜひ皆さんも実際に試してみてくださいね。
ではでは〜
「なぜか右足の袖だけが
自転車にこすれるので
汚れるんですが…」