はじめに
久しぶりにバーコード読み込み機能を動作させたらエラーが何件が発生した 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