何かやってみるブログ

興味をもったことに関して書いています。技術系の記事が多いです。

expo(ReactNative)でバーコードから本を検索する(後編) 動画付き

www.takayasugiyama.com

前回の記事の続きです。

まずはバーコードスキャナーの部分のUIを構築します。

バーコードスキャナーの部分のUIを構築する

import React, { useState, useEffect } from "react";
import { Text, StyleSheet, Button, SafeAreaView } from "react-native";
import { BarCodeScanner } from "expo-barcode-scanner";

export default function App() {
  const [hasPermission, setHasPermission] = useState(null);
  const [scanned, setScanned] = useState(false);

  useEffect(() => {
    (async () => {
      const { status } = await BarCodeScanner.requestPermissionsAsync();
      setHasPermission(status === "granted");
    })();
  }, []);

  const handleBarCodeScanned = ({ type, data }) => {
    setScanned(true);
    alert(`Bar code with type ${type} and data ${data} has been scanned!`);
  };

  if (hasPermission === null) {
    return <Text>Requesting for camera permission</Text>;
  }
  if (hasPermission === false) {
    return <Text>No access to camera</Text>;
  }

  const styles = StyleSheet.create({
    barcode: {
      width: "100%",
      height: "40%"
    },
    container: {
      flex: 1
    }
  });

  return (
    <SafeAreaView style={styles.container}>
      <BarCodeScanner
        onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
        style={styles.barcode}
      ></BarCodeScanner>
      {scanned && (
        <Button title={"Tap to Scan Again"} onPress={() => setScanned(false)} />
      )}
    </SafeAreaView>
  );
}

f:id:s-takaya1027:20200323034507j:plain

上のようになればOKです。

今回は楽天APIを使用していきます。

webservice.rakuten.co.jp

APIを使うためaxiosというライブラリを使用します。

github.com

% yarn add axios

axiosがpackage.jsonに追加されたことを確認したら、次に本の情報をaxiosで取得する処理を実装していきます。 Appファンクションコンポーネントに追記していきます。

  const [bookInfo, setBookInfo] = useState(null);


  const fetchBooks = async URL => {
    try {
      const response = await axios.get(URL);
      //本の情報を取得する
      setBookInfo(response.data.Items[0].Item);
    } catch (error) {
      alert("エラーが発生しました");
    }
  };

次にhandleBarCodeScannedファンクションを修正します。

 const handleBarCodeScanned = ({ type, data }) => {
    setScanned(true);
    const URL = `https://app.rakuten.co.jp/services/api/BooksTotal/Search/20170404?format=json&isbnjan=${data}&applicationId=${○○○○}`;
    fetchBooks(URL);
  };

applicationIdは楽天APIの利用登録したとき与えられるIdです。

本を再検索するときはstateの値たちをもとに戻します。

const resetSession = () => {
    setScanned(false);
    setBookInfo(null);
  };

本の情報を出力させるUIを追加した完成したコードが以下のようになります。

import React, { useState, useEffect } from "react";
import { Text, StyleSheet, Button, SafeAreaView, Image } from "react-native";
import { BarCodeScanner } from "expo-barcode-scanner";
import axios from "axios";

export default function App() {
  const [hasPermission, setHasPermission] = useState(null);
  const [scanned, setScanned] = useState(false);
  const [bookInfo, setBookInfo] = useState(null);

  useEffect(() => {
    (async () => {
      const { status } = await BarCodeScanner.requestPermissionsAsync();
      setHasPermission(status === "granted");
    })();
  }, []);

  const handleBarCodeScanned = ({ type, data }) => {
    setScanned(true);
    const URL = `https://app.rakuten.co.jp/services/api/BooksTotal/Search/20170404?format=json&isbnjan=${data}&applicationId=○○○○○`;
    fetchBooks(URL);
  };

  const fetchBooks = async URL => {
    try {
      const response = await axios.get(URL);
      //本の情報を取得する
      setBookInfo(response.data.Items[0].Item);
    } catch (error) {
      alert("エラーが発生しました");
    }
  };

  if (hasPermission === null) {
    return <Text>Requesting for camera permission</Text>;
  }
  if (hasPermission === false) {
    return <Text>No access to camera</Text>;
  }

  const styles = StyleSheet.create({
    barcode: {
      width: "100%",
      height: "40%"
    },
    container: {
      flex: 1
    }
  });

  const resetSession = () => {
    setScanned(false);
    setBookInfo(null);
  };

  return (
    <SafeAreaView style={styles.container}>
      <BarCodeScanner
        onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
        style={styles.barcode}
      ></BarCodeScanner>
      {scanned && (
        <Button title={"Tap to Scan Again"} onPress={() => resetSession()} />
      )}

      {bookInfo !== null ? (
        <>
          <Text>本のタイトル: {bookInfo.title}</Text>
          <Image
            source={{ uri: bookInfo.largeImageUrl }}
            style={{ width: 200, height: 200 }}
          />
        </>
      ) : null}
    </SafeAreaView>
  );
}

実機で確認するといかのようになります。

f:id:s-takaya1027:20200323050641p:plain
完成

www.youtube.com

感想

ネイティブアプリの機能でもExpoがAPIを提供してくれてありがたいなぁと思いました。