ReactとGoogle Books APIで本検索アプリを作る
今回はReactプロジェクトの中で、Google Books APIを使用し簡易的な本検索アプリを制作します。検索窓を設置し書籍のタイトルを入力して送信すると、情報を取得、結果をレンダリングします。
以下が完成形になります。
キャプチャの場合スクロールするとブコウスキーの関連書籍が続きます。
使用する主な技術
- React(create-react-appによる開発)
- ReactHooks(useState、useEffect、カスタムHook)
- Chakra UI(スタイルをあてる)
create-react-appでReactプロジェクトを作る
まずはReactの開発環境を構築していきましょう。ターミナルで以下のコマンドを打つだけです。(Node.jsのインストールが済んでることを想定しています。)
books-appの部分は自分の好きなプロジェクト名に変えていただいて問題ありません。
npx create-react-app books-app
Chakra UIをインストールする
以下のサイトに沿ってChakra UIをnpm installして設定していきます。
BooksSearchコンポーネントを作る
検索窓を設置するコンポーネントとしてBooksSearch.jsxを作成します。
import { Input } from '@chakra-ui/react';
import { Heading } from '@chakra-ui/react';
const BooksSearch = () => {
return (
<div>
<Heading as='h1' size='xl' mb='5'>Book Title</Heading>
<form className="text-xl">
<Input />
</form>
</div>
);
}
export default BooksSearch;
Chakra UIによって定義されたコンポーネントを使ってスタイルをあてています。
BooksResultコンポーネントを作る
検索結果をレンダリングするためのコンポーネントを作成します。
import { memo } from "react";
import { Text } from '@chakra-ui/react';
import { Heading } from '@chakra-ui/react';
const BooksResult = memo((props) => {
return (
<div>
<div className="mb-16">
</div>
</div>
)
})
export default BooksResult;
現状はほぼ空のコンポーネントになります。このコンポーネントはBooksSearchを親に持つ想定なので不要なレンダリングを避けるためにメモ化しています。
カスタムHookのuseSearch.jsを作る
hooksフォルダを作成、その中にuseSearch.jsを書いていきます。
import { useState } from 'react';
const useSearch = () => {
const [items, setItems] = useState([]);
const [value, setValue] = useState("");
const handleNewBooks = (event) => {
setValue(event.target.value);
};
const searchBooks = async (event) => {
event.preventDefault();
if (value === '') return;
const endpoint = 'https://www.googleapis.com/books/v1';
const res = await fetch(`${endpoint}/volumes?q=${value}`);
const data = await res.json();
const dataFormat = data.items.map(item => {
const Info = item.volumeInfo;
return {
title: Info.title,
description: Info.description,
link: Info.infoLink,
image: Info.imageLinks ? Info.imageLinks.smallThumbnail : '',
};
});
setItems(dataFormat);
}
return {handleNewBooks,searchBooks,items,value}
}
export default useSearch;
useStateでAPIからの返却値を格納するitemsと、検索窓にタイプする値を監視するvalueを定義します。
APIへのアクセスはfeachで行い、返ってきた値をフォーマットしてからsetItemsで更新しています。
そして全ての関数とstateをreturnしておきます。
BooksSearchコンポーネント追記
import useSearch from "../hooks/useSearch";
import BooksResult from "../components/BooksResult";
import { Input } from '@chakra-ui/react';
import { Heading } from '@chakra-ui/react';
const BooksSearch = () => {
const { handleNewBooks, searchBooks, value, items } = useSearch();
return (
<div>
<Heading as='h1' size='xl' mb='5'>Book Title</Heading>
<form onSubmit={searchBooks} className="text-xl">
<Input onChange={handleNewBooks} value={value} />
</form>
<BooksResult items={items} />
</div>
);
}
export default BooksSearch;
BooksResultコンポーネントの読み込みをして、propsにカスタムHookから持ってきたitemsを渡します。formにはsearchBooksをトリガーとして、検索窓に書籍のタイトルを記入後(handleNewBooks)、enterでAPIにアクセスします。
BooksResultコンポーネント追記
import { memo } from "react";
import { Text } from '@chakra-ui/react';
import { Heading } from '@chakra-ui/react';
const BooksResult = memo((props) => {
const { items } = props;
return (
<div>
<div className="mb-16">
{items.map((item, index) => {
return (<div className="text-lg m-8"
key={index}>
<a href={item.link} target='_blank' >
<img src={item.image} />
<div className='p16'>
<Heading as='h2' size='xl' mt='10'>{item.title}</Heading>
<Text align='justify' fontSize='xl' mt='10'>{item.description}</Text>
</div>
</a>
</div>)
})}
</div>
</div>
)
})
export default BooksResult;
フォーマットされたitemsをpropsで受け取り、それを元にmapでアクセスしてレンダリングしています。
App.jsを編集
最後にApp.jsにBookSearchコンポーネントを読み込みます。
import BooksSearch from './components/BooksSearch';
import './App.css';
import { ChakraProvider } from '@chakra-ui/react';
import { Container } from '@chakra-ui/react';
function App() {
return (
<ChakraProvider>
<div className="App">
<Container maxW='container.sm'>
<BooksSearch />
</Container>
</div>
</ChakraProvider>
);
}
export default App;
これで完成となります。
終わり
今回はReactとGoogle Books APIで簡易的な本検索アプリを作ってみました。Chakra UIはとても簡単にスタイルが整えられていいですね。引き続きReact学習していきます。
参考文献
Discussion