Reactを基本からまとめてみた【3】【WebAPIを用いた画像検索アプリ】

##はじめに

####学習するに至った経緯

2020年より、未経験からエンジニアへの転職を目指し、某プログラミングスクールへ通う。入学後、『Ruby』を未経験から学ぶ人が多いのと『Ruby』の求人が思っていた以上に少ないので、卒業後、フロントエンドのエンジニアを目指す事に。
Reactの学習した事を言語化し、認識の深化による備忘録として記載。

##検索フォームの作成

###APIとは
『API』とは、「Application Programming Interface」の略で、大雑把に訳すと「アプリケーションをプログラミングするためのインターフェース」という意味。
######※インターフェイスとは、コンピュータ用語でいうと、「何か」と「何か」をつなぐものという意味を持つ。　例:USBも「パソコン」と「周辺機器」をつなぐもので、インターフェイスの一つである。
つまり、『API』とは、「何か」と「何か」が「アプリケーション、ソフトウェア」と「プラグラム」をつなぐものという意味で、ソフトウェアの機能を共有する仕組み。

###WebAPIとは
『WebAPI』とは、コンピュータプログラムの提供する機能を外部の別のプログラムから呼び出して利用するための手順・規約（API：Application Programming Interface）の類型の一つで、HTTPなどWebの技術を用いて構築されたもの。
Webサイトに外部のサイトの提供する機能や情報を組み込んだり、アプリケーションソフトからWeb上で公開されている機能や情報を利用する際などに用いられる。


###WebAPIのメリット
① 開発効率が上がる。<br>検索機能を実装したい場合、自分でデータを用意して、インフラ、バックエンドの実装をしなくてすむ。
② 運用コストが減る。<br>インフラバックエンドは、APIを交換している会社がメンテナンスをする。
③ 最新の情報が入手できる。

##axios(アクシオス)とは
HTTP通信を超簡単に行うことができるJavaScriptライブラリ。
HTTP通信と言うと用途がわかりづらいが、主にJSONの取得に利用されることが多い。



###1. 検索バーの作成

####(1)　プロジェクトを新規作成する。
#####※ WebAPIは、(https://pixabay.com/ja/) を使用する。

```
terminal
create-react-app <ファイル名>
```

####(2)初期設定
① デフォルトのファイル全部削除
② semantic-uiの導入
[semantic-ui]
(https://cdnjs.com/libraries/semantic-ui)
semantic-ui の下記のソースコードを public / index.htmlにlinkタグで、貼り付ける。


```
https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css
```

③ index.jsの作成

``` index.js
import React from "react";

const App = () => {
  return (
    <div>
      <p>App</p>
    </div>
  );
};
export default App;
```
④ App.jsの作成

```App.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

ReactDOM.render(<App />, document.querySelector("#root"));
```
####(3)SearchBar.jsの作成
① src / components　を作成後、SearchBar.jsファイルを作成

```SearchBar.js
import React from "react";

const SearchBar = () => {
  return (
    <div>
      <p>SearchBar</p>
    </div>
  );
};

export default SearchBar;
```

```App.js
import React from "react";
import SearchBar from "./components/SearchBar";

const App = () => {
  return (
    <div>
      <SearchBar />
    </div>
  );
};

export default App;
```
② SearchBar.js　ファイルの中身の修正
[Semantic UI]
(https://semantic-ui.com/)

『Semantic UI』のFormを選択する。
Typsのソースコードをコピーし、SearchBar.jsのファイルの中身を書き換える。

```SearchBar.js
import React from "react";

const SearchBar = () => {
  return (
    <form className="ui form">
      <div className="field">
        <label>First Name</label>
        <input type="text" name="first-name" placeholder="First Name" />
      </div>
    </form>
  );
};

export default SearchBar;
```

③ 画面の余白を整える

```App.js
import React from "react";
import SearchBar from "./components/SearchBar";

const App = () => {
  return (
    <div className="ui container" style={{ marginTop: "20px" }}>
      <SearchBar />
    </div>
  );
};

export default App;
```
④ラベルとplaceholderを整える

```SearchBar.js
import React from "react";

const SearchBar = () => {
  return (
    <form className="ui form">
      <div className="field">
        <label>Image Search</label>
        <input type="text" name="search" placeholder="" />
      </div>
    </form>
  );
};

export default SearchBar;
```
⑤ Enterキーを押した際の動作の関数を定義する

#####event.preventDefault() <br>このメソッドが呼ばれると、通常実行されるアクションがキャンセルされる。

```SearchBar.js
import React from "react";

const SearchBar = () => {
  const onFormSubmit = (event) => {
    event.preventDefalt();
    console.log("onSubmit");
  };
  return (
    <form onSubmit={onFormSubmit} className="ui form">
      <div className="field">
        <label>Image Search</label>
        <input type="text" name="search" placeholder="" />
      </div>
    </form>
  );
};

export default SearchBar;
```
⑥ placeholder内に入力された文字列をstateで管理する

SearchBar.jsでuseStateを用いてstate管理を行う。

```SearchBar.js
import React, { useState } from "react";

const SearchBar = () => {
  const [term, setTerm] = useState("");
  const onFormSubmit = (event) => {
    event.preventDefalt();
    console.log("onSubmit");
  };
  return (
    <form onSubmit={onFormSubmit} className="ui form">
      <div className="field">
        <label>Image Search</label>
        <input
          type="text"
          name="search"
          placeholder=""
          value={term}
          onChange={(event) => {
            setTerm(event.target.value);
          }}
        />
      </div>
    </form>
  );
};

export default SearchBar;
```

⑦ console画面にユーザーが検索したキーワードを表示させる

App.jsの中身に実装する。

```App.js
import React from "react";
import SearchBar from "./components/SearchBar";

const App = () => {
  const onSearchSubmit = (term) => {
    console.log(term);
  };
  return (
    <div className="ui container" style={{ marginTop: "20px" }}>
      <SearchBar onSubmit={onSearchSubmit} />
    </div>
  );
};

export default App;
```

```SearchBar.js
import React, { useState } from "react";

const SearchBar = ({ onSubmit }) => {
  const [term, setTerm] = useState("");
  const onFormSubmit = (event) => {
    event.preventDefalt();
    onSubmit(term);
  };
  return (
    <form onSubmit={onFormSubmit} className="ui form">
      <div className="field">
        <label>Image Search</label>
        <input
          type="text"
          name="search"
          placeholder=""
          value={term}
          onChange={(event) => {
            setTerm(event.target.value);
          }}
        />
      </div>
    </form>
  );
};

export default SearchBar;

```

##2.画像データの一覧表示
(1)APIキーの取得
#####※ WebAPIは、(https://pixabay.com/ja/) を使用する。
① Pixabayを使用する。
ログイン　⇨ 写真検索　⇨ About ⇨ API　⇨ 『Get Started』⇨ <br> Parameters『key』『q』を使用する。
②API keyをコピーする。

(2)axiosの追加
terminalで、『yarn add axios』を実装する。<br>※axiosを用いて、HTTP通信を実現する。

(3)App.jsの修正

① pixabayへのHTTP通信を実装する。

```App.js
import React from "react";
import axios from "axios";
import SearchBar from "./components/SearchBar";

const App = () => {
  const onSearchSubmit = async (term) => {
    try {
      const params = {
        key: "",
        q: term,
      };
      const response = await axios.get("https://pixabay.com/api/", { params });
      console.log(response);
    } catch {}
  };
  return (
    <div className="ui container" style={{ marginTop: "20px" }}>
      <SearchBar onSubmit={onSearchSubmit} />
    </div>
  );
};

export default App;
```

② useStateを使用する。

```App.js
import React, { useState } from "react";
import axios from "axios";
import SearchBar from "./components/SearchBar";

const App = () => {
  const [images, setImages] = useState([]);
  const onSearchSubmit = async (term) => {
    try {
      const params = {
        key:,
        q: term,
      };
      const response = await axios.get("https://pixabay.com/api/", { params });
      setImages(response.data.hits);
      if (response.data.total === 0) {
        window.alert("お探しの画像はありません。");
      }
    } catch {
      window.alert("写真の取得に失敗しました");
    }
  };
  return (
    <div className="ui container" style={{ marginTop: "20px" }}>
      <SearchBar onSubmit={onSearchSubmit} />
    </div>
  );
};

export default App;
```

(4)imageList.jsの作成
 componets / imageList.jsファイルを作成する。

```imageList.js
import React from "react";

const ImageList = (props) => {
  const images = props.images.map((image) => {
    return (
      <a href={image.pageURL} key={image.id} target="_blank" rel="noopener noreferrer" className="ui medium image">
        <img src={image.webformatURL} alt={image.tags} />
      </a>
    );
  });
  return <div>{images}</div>;
};

export default ImageList;
```

(5)App.jsの修正

imageListのimportする

```App.js
import React, { useState } from "react";
import axios from "axios";
import SearchBar from "./components/SearchBar";
import ImageList from "./components/imageList";

const App = () => {
  const [images, setImages] = useState([]);
  const onSearchSubmit = async (term) => {
    try {
      const params = {
        key: "",
        q: term,
      };
      const response = await axios.get("https://pixabay.com/api/", { params });
      setImages(response.data.hits);
      if (response.data.total === 0) {
        window.alert("お探しの画像はありません。");
      }
    } catch {
      window.alert("写真の取得に失敗しました");
    }
  };
  return (
    <div className="ui container" style={{ marginTop: "20px" }}>
      <SearchBar onSubmit={onSearchSubmit} />
      <ImageList images={images} />
    </div>
  );
};

export default App;
```

##3.スタイルの修正
(1)環境変数の導入
①.evn.localの作成
.gitignoreと同じ所に、.evn.localの作成する。

```.evn.local
REACT_APP_PIXABAY_APIKEY = ""
```

```App.js
import React, { useState } from "react";
import axios from "axios";
import SearchBar from "./components/SearchBar";
import ImageList from "./components/imageList";

const App = () => {
  const [images, setImages] = useState([]);
  const ApiKey = process.env.REACT_APP_PIXABAY_APIKEY;
  const onSearchSubmit = async (term) => {
    try {
      const params = {
        key: ApiKey,
        q: term,
      };
      const response = await axios.get("https://pixabay.com/api/", { params });
      setImages(response.data.hits);
      if (response.data.total === 0) {
        window.alert("お探しの画像はありません。");
      }
    } catch {
      window.alert("写真の取得に失敗しました");
    }
  };
  return (
    <div className="ui container" style={{ marginTop: "20px" }}>
      <SearchBar onSubmit={onSearchSubmit} />
      <ImageList images={images} />
    </div>
  );
};

export default App;
```

(2)react-masonry-componetの導入

#####Masonryとは指定した要素を自動的にタイル状に並べてくれるライブラリのこと。

①react-masonry-componetを作成する。

```
yarn add react-masonry-componet
```

[eiriklv/react-masonry-component]
(https://github.com/eiriklv/react-masonry-component)

②ImageList.jsを書き換える。

```ImageList.js
import React from "react";
import Masonry from "react-masonry-component";

const ImageList = (props) => {
  const images = props.images.map((image) => {
    return (
      <a href={image.pageURL} key={image.id} target="_blank" rel="noopener noreferrer" className="ui medium image">
        <img src={image.webformatURL} alt={image.tags} />
      </a>
    );
  });
  return <Masonry className="image-list">{images}</Masonry>;
};

export default ImageList;
```

(3)pixabaylogoの挿入
① Pixabay APIのlogoをクリックし、マークをダウンロードする。
② ダウンロードしたものをsrcに入れる。
③ App.jsファイルに画像を挿入する。

```App.js
import React, { useState } from "react";
import axios from "axios";
import SearchBar from "./components/SearchBar";
import ImageList from "./components/imageList";
import logo from "./pixabay-logo.png";

const App = () => {
  const [images, setImages] = useState([]);
  const ApiKey = process.env.REACT_APP_PIXABAY_APIKEY;
  const onSearchSubmit = async (term) => {
    try {
      const params = {
        key: ApiKey,
        q: term,
      };
      const response = await axios.get("https://pixabay.com/api/", { params });
      setImages(response.data.hits);
      if (response.data.total === 0) {
        window.alert("お探しの画像はありません。");
      }
    } catch {
      window.alert("写真の取得に失敗しました");
    }
  };
  return (
    <div className="ui container" style={{ marginTop: "20px" }}>
      <img src={logo} alt="pixabay-logo" className="pixabay-logo" />
      <SearchBar onSubmit={onSearchSubmit} />
      <ImageList images={images} />
    </div>
  );
};

export default App;
```
(4)src / Styles / ImageList.cssの作成

```ImageList.css
.pixabay-logo {
    width: 200px;
}

.image-list .ui.medium.image {
    width: 25%;
    padding: 0 3px 3px;
}

.image-list .ui.medium.image img {
    width: 100%;
    height: 100%;
}

```



##参考サイト
[【React入門】#8-1 WebAPIを用いた画像検索アプリ ~検索フォームの作成~]
(https://www.youtube.com/watch?v=2PdVUO7FitM)
[今さら聞けないIT用語：やたらと耳にするけど「API」って何？]
(https://data.wingarc.com/what-is-api-16084)
[Web API 【Web Application Programming Interface】 ウェブAPI]
(https://e-words.jp/w/Web_API.html)
[【React入門】#8-2 WebAPIを用いた画像検索アプリ ~画像検索機能の作成~]
(https://www.youtube.com/watch?v=tclzlcdKUlI)
[1分でわかるJavaScriptライブラリaxiosの超簡単な使い方]
(https://iwb.jp/javascript-library-axios-howto/)
[【React入門】#8-3 WebAPIを用いた画像検索アプリ ~スタイルの修正~]
(https://www.youtube.com/watch?v=4oawSYbY2Zg&t=12s)