deve.K

エンジニアが未来を切り開く。

React Hooks API fetchで取得

react画像

本日はReactのHooksでfetchを使用しAPIを叩いてみましょう。

ReactのクラスではAJAXコールというのがあります AJAXライブラリをReactと組み合わせます。

AJAX コールでのデータ取得はcomponentDidMount のライフサイクルメソッドを使いsetStateメソッドで更新していきます。

Hooksの場合はライフサイクルと言えば、useEffectを使用しuseStateで更新します。

本日はクラスは置いといて、関数コンポーネントのHooksによるAPI呼び出しになります。

Hooks(フック)

React16.8から追加されたクラスを使用せずともstateやその他の機能を使用でき関数コンポーネントにReact状態を追加し実装する事が可能です。

フックが使用された、関数コンポーネントはステートフルなコンポーネントとなります。

useEffectフックとは

useEffectフックを使用すると、関数コンポーネントで副作用を実行することができます。

副作用の主な例は、データのフェッチリクエスト、DOMの直接な変更、タイマー関数などです。

useEffectフックは、レンダリングされた要素が画面に描画された後に、非同期として実行されます。

本日はfetchメソッドを使用しデータを呼び出していきます。

JavaScriptに精通してる方ならお馴染みのメソッドです。

それではReactで学習する際のお決まりであるcreate-react-app(CRA)を使用していきます。

構築が手っ取り早いのでこういうのは、活用していきましょう。

インストール方法が分からない方はこちらから。

フックを使用したAPI呼び出し

まずは必要なモジュールをimportし、useEffect()とuseState()フックを読み込みます。

import { useEffect, useState } from 'react';

全体図コード

// App.js

const App = () => {

  const [posts, setPosts] = useState([])

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
    .then(res => res.json())
    .then(data => {setPosts(data)
    })
  },[])

const usePosts = posts.map((post, index)=>{
 return <div key={index}>
<li>{post.id}</li>
<li>{post.title}</li>
</div> 
})

return (
<div>
 <ul>
     {usePosts}
 </ul>
</div>
    );
  }
export default App;

出力の確認は下記のCodepenで確認できます。

See the Pen Untitled by dev.K | Webアプリ開発者 (@enjinia_f) on CodePen.


コードの解説をします。

useStateフックの初期値は空の配列で設定します。

const [posts, setPosts] = useState([])

まず、useState()メソッドの状態フックは初期状態で呼び出されます。

フックは、現在の状態とそれを更新する関数の2つの値を返します

useEffectフックでコンポーネントのマウント時の処理を追加しfetchでダミー用で提供されているURLを使用しAPIのリクエストを送信をします。

useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')

そして、useEffectフックの第2引数に空の配列を渡す事によって、監視する状態変数はなくなります。

なので監視する必要がなくなるのでフックは1回だけ、第1引数の関数が実行されます。

つまりコンポーネントがマウントされた際にコールバックを1回だけフックさせるには、空の配列を2番目の引数に渡す必要がある と言うことになります。

useStateフックはコールバックをサポートされていませんので、コールバックはuseEffectフックを使用し実現させます。

useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts')
    .then(res => res.json())
    .then(data => {setPosts(data)
    })
  },[]) //空の配列を渡す

もし空の配列を渡し忘れると非同期処理の無限ループが起こる可能性があります。

そうなりますと、不要な再レンダリングが発生していることになります。

気を付けて扱って下さい。

最初のthen()でjson形式で取得し、次のthen()でデータを保存しpostsのstateに格納してます。

fetch('https://jsonplaceholder.typicode.com/posts')
    .then(res => res.json())
    .then(data => {setPosts(data)

マップ関数を使用しliタグを新しく配列として生成しデータをブラウザ上に表示していきます。

const usePosts = posts.map((post, index)=>{
    return <div key={index}>
<li>{post.id}</li>
<li>{post.title}</li>
 </div> 
});

ここから、fetchで呼び出した際に初学者様が引き起こしそうなエラーを下記に示します。

下記では、undefinedのエラーが返されます。

先述のおさらいも含めまして、なぜエラーが返されるのか問題解決を試みて下さい。

const App = () => {

const [posts, setPosts] = useState()

useEffect( () => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res => res.json())
.then(data => setPosts(data))
  }, [])

posts.map((post) => console.log(post))
    
return (
   <div></div>
    );
  }
//出力

Uncaught TypeError: Cannot read properties of undefined (reading 'map')

codepen.io/API呼び出しのundefinedエラー

上記では、エラーのログを実際に確認できます。

それでは、エラー解決していきます。

これは、useStateフックの初期値を設定していないためundefined(未定義)のエラーが返されます。

const [posts, setPosts] = useState()

デフォルトの初期値として空の配列を渡してあげれば、エラーが返される事はなくログに出力されます。

const [posts, setPosts] = useState( [] )

codepen.io/API呼び出しエラー解決

状態を空の配列で初期化をしてあげなればいけません。

このような、一般的な間違いに気を付けるようにして下さい。

最後に

フックでAPIをフェッチする際は、useEffectフックの副作用がどのように機能するのかをしっかりと理解する事が重要となります。

無数の再レンダリングを回避する方法は、useCallback()フックと併用すると回避可能です。

useStateとuseEffectフックに関する、深い知識を学びたい方は下記を参考下さい。

dev-k.hatenablog.com

dev-k.hatenablog.com

dev-k.hatenablog.com

dev-k.hatenablog.com

fetchは基本的にはasync/awaitの構造体として呼び出すようにしてください。

外部リソースではpromiseによって呼び出されるのが一般的です。

その方法はまた別途、記事に致します。

本日は以上となります。

最後までこの記事を読んで頂きありがとうございます。

プライバシーポリシー