はじめに
久しぶりにバーコード読み込み機能を動作させたらエラーが何件が発生した px-wing.hatenablog.com
1件目は下記のエラー
index.js:1 Warning: validateDOMNesting(...): <tr> cannot appear as a child of <table>. Add a <tbody>, <thead> or <tfoot> to your code to match the DOM tree generated by the browser. in tr (at BarcodeScan.js:90)
- 2件目はYahooAPIの商品検索が実行できない。
原因と解決方法
1件目の対応はReactでtableタグを出力する際はtbodyタグが必要ということでtbodyタグを追加することで解消できた。 github.com
2件目のForbiddenエラーが発生した 原因を調べるとアクセス制限数が上限を超えているというエラーだが、利用数の上限を超えるほど利用していないため、調査したところ、YahooAPIの検索の仕様が変わっていたい
修正前
const result = await axios.get(`https://shopping.yahooapis.jp/ShoppingWebService/V1/json/itemSearch?appid=<あなたのAPIKey>&jan=${req.query.barcode} .then(res =>{ return res.data.ResultSet[0].Result[0] })
修正後
const result = await axios.get(`https://shopping.yahooapis.jp/ShoppingWebService/V3/itemSearch?appid=<あなたのAPIKey>&jan_code=${req.query.barcode}.then(res =>{ return res.data.hits[0] })
YahooAPIの変更点
- エンドポイントのURLの変更
- パラメータの変更
- レスポンスで出力されるJsonの形式
実際に変更したプログラム
Express側
router.get('/product_search', async (req, res, next) =>{ logger.app.debug(req.query.barcode) const result = await axios.get(`https://shopping.yahooapis.jp/ShoppingWebService/V3/itemSearch?appid=<あなたのAPIキー>&jan_code=${req.query.barcode}`) .then(res =>{ return res.data.hits[0] }) res.json(result) })
React
import React , { useState,useEffect } from 'react' import Quagga from "quagga"; import axios from 'axios' const BarcodeScan = (props) => { const [barcode,setBarcode] = useState("") const [product,setProduct] = useState({}) const barcodeApi = async (barcode) => { const result = await axios.get(`https://<express側のURLを指定する>?barcode=${barcode}`) .then(res =>{ const endAnnounce = new SpeechSynthesisUtterance("読み込みました") speechSynthesis.speak(endAnnounce) console.log(res.data) return setProduct(res.data) }) console.log(result) } const config = { inputStream: { name : "Live", type : "LiveStream", target: '#preview', size: 1000, singleChannel: false }, locator: { patchSize: "medium", halfSample: true }, decoder: { readers: [{ format: "ean_reader", config: {} }] }, numOfWorker: navigator.hardwareConcurrency || 4, locate: true, src: null }; useEffect(() => { Quagga.onDetected(result => { if (result !== undefined){ setBarcode(result.codeResult.code) } }); Quagga.init(config, function(err) { if (err) { console.log(err); return } Quagga.start(); }); },[]) useEffect(() => { console.log(barcode) if (barcode){ Quagga.stop() barcodeApi(barcode) Quagga.init(config, function(err) { if (err) { console.log(err); return } Quagga.start(); }); } },[barcode]) return ( <> <h2>バーコードスキャナ</h2> <hr /> {barcode !== "" ? `バーコード:${barcode}` : "スキャン中"} <hr /> { Object.keys(product).length ? <table> <tbody> <tr> <td>商品名</td> <td><a href={product.url}>{product.name}</a></td> </tr> <tr> <td>商品詳細</td> <td>{product.description}</td> </tr> <tr> <td>商品画像</td> <td>{product.image ? <img src={product.image.small} /> : '画像はありません'}</td> </tr> </tbody> </table> : '' } <div id="preview"></div> </> ) } export default BarcodeScan