Next.js+supabaseで商品成分サーチアプリを作ってみた話２（バーコードリーダー）

※初心者のため、間違いや何かご存じの方がいましたら、教えていただけると助かります。

# 作ったもの
https://keshohin-seibun.vercel.app/

# 概要
今回のアプリで、typescriptで使えるバーコードリーダーライブラリとして、Quagga.jsとZXingが候補に挙がった。
どちらを使うか。

### 環境
windows11
docker-desktop
Next.js(app routerを使用)
supabase
ホスティング：Vercel

## 内容

以下は、BingAIにまとめてもらった表。

| 特徴            | Quagga.js                                                                 | ZXing                                                                 |
|-----------------|---------------------------------------------------------------------------|----------------------------------------------------------------------|
| **言語**        | JavaScript                                                                | Java, JavaScript, C++, C#, Objective-C, Python, Rust, etc.           |
| **対応バーコード** | EAN, Code 128, Code 39, Interleaved 2 of 5, UPC, etc.                    | QR Code, Data Matrix, Aztec, PDF 417, EAN, UPC, Code 128, etc.       |
| **ブラウザ対応** | はい                                                                     | はい                                                                 |
| **モバイル対応** | はい                                                                     | はい                                                                 |
| **ライセンス**  | MIT License                                                               | Apache License 2.0                                                   |
| **ドキュメント** | 比較的少ない                                                              | 豊富                                                                 |
| **パフォーマンス** | 高速だが、特定のバーコードに最適化されている                              | 幅広いバーコードに対応しており、全体的に高性能                       |
| **コミュニティ** | 活発だが、ZXingほど大きくはない                                           | 非常に活発で広範囲                                                   |
| **使用例**      | ウェブアプリケーションでのバーコードスキャン                               | モバイルアプリケーション、デスクトップアプリケーション、ウェブアプリケーション |

Quaggaは高速だが、1Dコードしか対応していない。
ZXingは少し遅い？が、2Dコード（QRコード）にも対応。

## 各コード例（components/BarcodeScanner.tsx）
Quagga.js（今回、Quaggaは、以下のコードではうまく動かなかった。ビデオは起動するが、読み取ってくれない。原因までわからず。）
```
import Quagga from "quagga";
import { useEffect, useRef, useState } from "react";

interface BarcodeScannerProps {
    onScan: (code: string) => void;
}

const BarcodeScanner: React.FC<BarcodeScannerProps> = ({ onScan }) => {
    const [scanning, setScanning] = useState(false);
    const videoRef = useRef<HTMLVideoElement>(null);

    useEffect(() => {
        if (scanning) {
            Quagga.init(
                {
                    inputStream: {
                        type: "LiveStream",
                        target: videoRef.current,
                        constraints: {
                            facingMode: "environment",
                        },
                    },
                    decoder: {
                        readers: [
                            "code_128_reader",
                            "ean_reader",
                            "ean_8_reader",
                            "code_39_reader",
                            "code_39_vin_reader",
                            "codabar_reader",
                            "upc_reader",
                            "upc_e_reader",
                            "i2of5_reader",
                        ],
                    },
                },
                (error: any) => {
                    if (error) {
                        console.log(error);
                        setScanning(false);
                        return;
                    }
                    Quagga.start();
                }
            );
        }

        return () => {
            if (scanning) {
                Quagga.stop();
            }
        };
    }, [scanning, onScan]);

    return (
        <div>
            <button
                style={{　　　　　//css調整
                    width: "50%",
                    margin: "0 auto",
                    display: "block",
                    border: "1px solid black",
                }}
                onClick={() => setScanning(true)}
            >
                バーコードスキャン
            </button>
            {scanning && (
                <div
                    ref={videoRef}
                    style={{ width: "80%", height: "50%", margin: "0 auto" }}　　　　　//css調整
                />
            )}
        </div>
    );
};

export default BarcodeScanner;
```
<br>

ZXing 
```
import { BrowserMultiFormatReader } from "@zxing/library";
import { useEffect, useRef, useState } from "react";

const BarcodeScanner = ({ onScan }: { onScan: (code: string) => void }) => {
    const [scanning, setScanning] = useState(false);
    const videoRef = useRef<HTMLVideoElement>(null);

    useEffect(() => {
        if (scanning) {
            const codeReader = new BrowserMultiFormatReader();
            codeReader.decodeFromVideoDevice(
                null,
                videoRef.current,
                (result, err) => {
                    if (result) {
                        onScan(result.getText());
                        setScanning(false);
                        codeReader.reset();
                    }
                }
            );
        }
    }, [scanning, onScan]);

    return (
        <div>
            {!scanning ? (
                <button
                    style={{ 　　　　　//css調整
                        width: "50%",
                        height: "100px",
                        margin: "0 auto",
                        display: "block",
                        border: "1px solid black",
                        backgroundColor: "white",
                        font: "bold 18px sans-serif",
                    }}
                    onClick={() => setScanning(true)}
                >
                    バーコードで検索<br></br>（カメラを起動）
                </button>
            ) : (
                "カメラ起動"
            )}
            {scanning && (
                <video
                    ref={videoRef}
                    style={{　　　//css調整
                        width: "90%",
                        height: "60%",
                        margin: "0 auto",
                    }}
                />
            )}
        </div>
    );
};

export default BarcodeScanner;
```

## まとめ
最終的に、「商品の同一性」判定が目的であり、将来的にバーコードが2DのQRコードに変わっていく可能性も考え、ZXingを利用することにした。
ここで読み取ったコードをもとに、yahoo shoppingAPIを叩いて該当商品があれば商品名を取得する。もし、登録済み商品のデータがあれば、その情報を表示する仕様にした。
次回は、本アプリで検索機能を何度か実装したので、それに関する備忘録を残す予定。

<br/>

https://qiita.com/yassyjk/items/39406ae25376b7d64c71