【備忘録】Next.jsでQRコード生成と読み込み

# きっかけ
QRコードを使用してデータを取得したい
# したこと
２つのライブラリを使用
* qrcode.react
    ```:生成するためのライブラリ
    npm install qrcode.react
    ```
* jsqr
    ```:読み込むためのライブラリ
    npm install jsqr --save
    ```
## QRコード生成
生成の方は簡単でqrcode.reactをimportしてQRコードにいれたい値とサイズを指定するだけです
```page.tsx
import { QRCodeCanvas } from "qrcode.react"

export default function Page(){
    return(
        <QRCodeCanvas value="適当な値" size="お好みで">
    )
}
```
ただしcanvasで生成されるので注意が必要です。
## QRコード読み取り
まずカメラの取得し、その情報からcanvasに変換をし、そのcanvasからQRコードか判別します。
```qr_camera.tsx
import {useState, useEffect, useRef} from 'react'
import jsQR from 'jsqr'

export default function Qr_Camera(){
    const videoRef = useRef<HTMLVideoElement>(null)
    const canvasRef = useRef<HTMLCanvasElement>(null)

    const [contentWidth, setContentWidth] = useState<number>(カメラの横幅)
    const [contentHeight, setContentHeight] = useState<number>(カメラの縦幅)
    useEffect(() => {
        const config = { audio:false, video: { facingMode: "environment" }}
        const ctx = canvasRef.current?.getContext('2d')
        const canvasUpdate = () => {
            if (ctx && videoRef.current && canvasRef.current) {
                canvasRef.current.width = contentWidth
                canvasRef.current.height = contentHeight
                ctx.drawImage(videoRef.current, 0, 0, contentWidth, contentHeight)
                requestAnimationFrame(canvasUpdate)
            }
        }
        const checkImage = async() => {
            if(ctx && videoRef.current){
                ctx?.drawImage(videoRef.current, 0, 0, contentWidth, contentHeight)
                const imageData = ctx.getImageData(0, 0, contentWidth, contentHeight)
                if (imageData) {
                    const code = jsQR(imageData.data, contentWidth, contentHeight)
                    if (code) {
                        // QRコードの情報が表示されます
                        console.log(code.data)
                    }
                }
                setTimeout(()=>{ checkImage() }, 200);
            }
        }
    
        navigator.mediaDevices.getUserMedia(config)
        .then(stream => {
            if (videoRef.current) {
                videoRef.current.srcObject = stream
                videoRef.current.onloadedmetadata = () => {
                    if (videoRef.current){
                        videoRef.current.play()
                        setContentWidth(videoRef.current.clientWidth)
                        setContentHeight(videoRef.current.clientHeight)
                        canvasUpdate()
                        checkImage()
                    }
                }
            }
        })
        .catch(err => {
            console.log(err)
        })
    },[contentWidth, contentHeight])

    return(
        <>
            // 今回はvideoをカメラとして使用していますがcanvasでも可です
            <video ref={videoRef} autoPlay playsInline width={contentWidth} height={contentHeight}></video>
            // tailwindCSSを使用していますが単純なcssでhiddenにしても大丈夫です
            <canvas ref={canvasRef} className='hidden'></canvas>
        </>
    )
}
```
# まとめ
QRコードの生成はqrcode.reactで簡単に実装でき、QRコードの読み込みはカメラの設定に苦戦したがしたいことができて満足しました
# 参考
https://qiita.com/U_sagi/items/12cc39487a863e0136a0

https://qiita.com/kan_dai/items/4331aae12f5f2d3ad18d#%E5%8F%96%E5%BE%97%E3%81%97%E3%81%9F%E7%94%BB%E5%83%8F%E3%83%87%E3%83%BC%E3%82%BF%E3%81%8B%E3%82%89qr%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E5%8F%96%E5%BE%97