昨年バズってた以下記事の課題1個目をやってみました
https://qiita.com/rana_kualu/items/915345b8f3f870cfe2aa
Hooks超便利!って思ったので覚書程度に残しておきます
書き方も適当なので、ここはこう書いた方が!ってことがあればコメントいただけると
Hooksについて
公式によると
フック (hook) は React 16.8 で追加された新機能です。state などの React の機能を、クラスを書かずに使えるようになります。
とのこと(https://ja.reactjs.org/docs/hooks-intro.html)
今回はHooksの useState
と useEffect
を使って進めていきます。
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)
作り方としては
- 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コンポーネントをレンダリングさせるためだけです
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
ReactDOM.render(<App />, document.querySelector("#root"));
App.jsを以下のようにするとhelloworld!意外に簡単。
import React from "react";
const App = () => {
return (
<div>hello world</div>
);
};
export default App;
App.js (indexに何を表示させるか)
今回はhelloworldじゃなくて映画の検索がしたいので
- 検索バー
- 表示するリスト
の2つが必要です。
render以下に検索バーとリストがあればいいので、要素としては以下のように書いていきます。
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として保持します
// 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という名前で検索機能を作っていきます。
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)
//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として切り出します。
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とか関係ないので、適当に作っていきます
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;
完成
寂しいのでcssにemotion
と、react-use
使ってtoggle入れて画像とか文字出しわけたりして遊んでました。
Leonの時のナタリーポートマン11歳って天才すぎると思いました。
参考記事
公式: https://ja.reactjs.org/docs/hooks-intro.html
Hooks解説: https://qiita.com/Mitsuzara/items/98d1bc4a83265a764084