ReactHooksを使ってAPI検索

昨年バズってた以下記事の課題１個目をやってみました
https://qiita.com/rana_kualu/items/915345b8f3f870cfe2aa
Hooks超便利！って思ったので覚書程度に残しておきます:writing_hand:
書き方も適当なので、ここはこう書いた方が！ってことがあればコメントいただけると:pray:

#Hooksについて
公式によると
> フック (hook) は React 16.8 で追加された新機能です。state などの React の機能を、クラスを書かずに使えるようになります。

とのこと（https://ja.reactjs.org/docs/hooks-intro.html）
今回はHooksの `useState` と `useEffect` を使って進めていきます。

## useState
クラスコンポーネントを使わずにstateを持つことができる機能。以下のように使います。
（実際の使い方はもっと下に）

```react
const [currentValue, setCurrentValue] = useState(initialValue)
  // currentValue     : 使用する変数の名前
  // setCurrentValue  : 使用する関数の名前
  // useState         : Reactのメソッド
  // initialValue     : stateにいれる最初の値
```

## useEffect
レンダリングの後になんらかの処理を動作させる。`ComponentDidMount` みたいな機能。
第二引数に配列を与えることで、特定の値が変化した時のみ動作させるようにすることができる。

```js
useEffect(() => {
    // レンダリングの後になんらかの処理を動作させるメソッド。
    fetchData(data);
  }, [data]);
  // 第二引数に配列を与えると、最初のレンダリング時と、
  // 値が変更された時のみメソッドが動く
```

この方の記事がわかりやすかったです！
https://qiita.com/Mitsuzara/items/98d1bc4a83265a764084

#Build a movie search app using React (with hooks)
こちら作って行きます。(完成イメージ↓）
![kbYsxsxb2D7mBhdlEmUrpMhRmOcQoR79vtT1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325594/86c14e87-3f01-3b50-e386-65b37442be6c.jpeg)

作り方としては
- APIを使った検索機能
- 検索結果を表示するリスト
- 検索結果の詳細を表示するアイテム

の3つがあれば作れそうです。

## 環境構築
便利なのでcreate-react-app使います。
create-react-appが入ってなかったらインストールします。
公式：https://ja.reactjs.org/docs/create-a-new-react-app.html

```
$ yarn global add create-react-app
$ create-react-app hooks_search
```

作ったらこんな感じになってるはず

```
├── README.md
├── node_modules
├── package.json
├── public
├── src
└── yarn.lock
```
srcフォルダ下を触りますが、最初のファイルは全部いらないので削除します。
必要なファイルを作って…


```
├── src
│   ├── components
│   │   ├── App.js　（indexに描画するファイル）
│   │   ├── MovieItem.js (検索結果の詳細）
│   │   ├── MovieList.js　（検索結果のリスト）
│   │   └── SearchMovie.js　（検索機能）
│   └── index.js (大本のファイル）
```

こんな感じで進めます

###index.js

HTMLの`#root`にAppコンポーネントをレンダリングさせるためだけです

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

ReactDOM.render(<App />, document.querySelector("#root"));
```

App.jsを以下のようにするとhelloworld!意外に簡単。

```Components/App.js
import React from "react";

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

export default App;
```

### App.js (indexに何を表示させるか）

今回はhelloworldじゃなくて映画の検索がしたいので
- 検索バー
- 表示するリスト
の2つが必要です。

render以下に検索バーとリストがあればいいので、要素としては以下のように書いていきます。

```Components/App.js
import React from "react";
import MovieList from "./MovieList";

const App = () => {
  return (
    <div>
      <input
        type="text"
        placeholder="SearchWord"
      />
      <MovieList />
    </div>
  );
};

export default App;
```

次に`useState`を使ってinputに入力した値をstateとして保持します

```Components/App.js
// useStateはreactからimport
import React, { useState } from "react";
import MovieList from "./MovieList";

const App = () => {
  const [searchWord, setSearchWord] = useState("");
  // const [currentValue, setCurrentValue] = useState(initialValue)
  // currentValue     : 使用する変数の名前
  // setCurrentValue  : 使用する関数の名前
  // useState         : Reactのメソッド
  // initialValue     : stateにいれる最初の値

  // 入力された値をstate保持させる関数
  const handleChange = e => {
    setSearchWord(e.target.value);
  };

  return (
    <div>
      <input
        type="text"
        placeholder="SearchWord"
        //値が変わるたびにhandleChangeを動かす
        onChange={handleChange}
      />
      //MovieListにsetSearchWordで保持したsearchWordを渡す
      <MovieList word={searchWord} />
    </div>
  );
};

export default App;
```

MovieListにsearchWordを渡して表示させて行くのですが
先にsearchMovieという名前で検索機能を作っていきます。

```Components/MovieList.js
import React from "react";
import searchMovie from "./SearchMovie";

const MovieList = ({ word }) => {
  // searchWordを使ってsearchMovieメソッドを動かし、値をmovieListに代入
  const movieList = searchMovie(word);

  return (
    :
    :
  );
};

export default MovieList;

```

###SearchMovie.js　（検索機能）

App.jsで受け取ったsearchWordを映画を検索する機能を作っていきます！
- APIを叩いてjsonデータを取得
- jsonデータをListに表示させる

APIはtheMovieDBが公開している無料APIを使っていきます！
登録必要なので以下参考に
（https://www.themoviedb.org/documentation/api?language=ja）


```Components/searchMovie.js
//useState と useEffectをreactからimport
import { useState, useEffect } from "react";
//API通信はaxiosを使います
import axios from "axios";
//apikeyはそのまま書いちゃダメなのでenvに入れて呼び出します（他にいいやり方あるのかな？）
const apikey = process.env.REACT_APP_MOVIE_API_KEY;

const SearchMovie = word => {
　// 先ほどと同じようにMovieListにAPI通信結果をstate保持させていきます。
  const [movieList, setMovieList] = useState([]);
  const fetchMovie = async word => {
    const response = await axios.get(
      `https://api.themoviedb.org/3/search/movie?api_key=${apikey}&query=${word}`
      // 持ってきたwordはここのAPI処理に使われる
    );
    const data = response.data.results;
    setMovieList(data);
    // APIで返る値をmoviesに保持
  };

  useEffect(() => {
    // レンダリングの後になんらかの処理を動作させるメソッド。
    fetchMovie(word);
  }, [word]);
  // 第二引数に変数を与えると、最初のレンダリング時と、
  // 変数の値が変更された時のみメソッドが動く

  return movieList;
};

export default SearchMovie;

```


###MovieList (検索結果のリスト）
次にリストを作成していきます。
長くなってしまうのでListからそれぞれのデータを渡して個別のMovieItemとして切り出します。

```Components/MovieList.js
import React from "react";
import searchMovie from "./SearchMovie";
import MovieItem from "./MovieItem";

const MovieList = ({ word }) => {
  const movieList = searchMovie(word);

  return (
    <div>
      <ul>
         // movieListに配列が返ってきているのでmap処理 
        {movieList.map(movie => (
          <MovieItem movie={movie} key={movie.id} />
        ))}
      </ul>
    </div>
  );
};

export default MovieList;


```

###MovieItem (個別のItemの表示）
Listから受け取ったデータを表示させていくだけなのでHooksとか関係ないので、適当に作っていきます

```Components/MovieItem.js
import React from "react";


const MovieItem = ({ movie }) => {
  
  return (
    <li>
      <p>{movie.title}</p>
      <div>
        // 画像無い場合はNoImageと表示（画像用意するの面倒だった）
        {movie.poster_path ? (
          <img
            className={movieImg}
            src={`http://image.tmdb.org/t/p/w500/${movie.poster_path}`}
            alt=""
          />
        ) : (
          <p>NoImage</p>
        )}
       
      <p>{movie.overview}</p>
    </li>
  );
};

export default MovieItem;

```
# 完成
これで完成です！
<img width="803" alt="スクリーンショット 2020-03-11 12.25.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325594/5fc61353-bae6-069c-06d1-efaa24a143a5.png">

寂しいのでcssに`emotion`と、`react-use`使ってtoggle入れて画像とか文字出しわけたりして遊んでました。
Leonの時のナタリーポートマン１１歳って天才すぎると思いました。

# 参考記事
公式： https://ja.reactjs.org/docs/hooks-intro.html
Hooks解説： https://qiita.com/Mitsuzara/items/98d1bc4a83265a764084