Help us understand the problem. What is going on with this article?

ReactHooksを使ってAPI検索

昨年バズってた以下記事の課題1個目をやってみました
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の useStateuseEffect を使って進めていきます。

useState

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

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

useEffect

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

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

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

Build a movie search app using React (with hooks)

こちら作って行きます。(完成イメージ↓)
kbYsxsxb2D7mBhdlEmUrpMhRmOcQoR79vtT1.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コンポーネントをレンダリングさせるためだけです

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;

完成

これで完成です!
スクリーンショット 2020-03-11 12.25.18.png

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

参考記事

公式: https://ja.reactjs.org/docs/hooks-intro.html
Hooks解説: https://qiita.com/Mitsuzara/items/98d1bc4a83265a764084

Sotq_17
フロントエンド💻 趣味は東南アジアでのんびり安ビールを飲むことです🧟‍♂️
wiz_inc
Wizは、最新のIoTやICTサービスをお客様に届ける「ITの総合商社」です
http://012grp.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away