web-dev-qa-db-ja.com

Reactでフックを使用してAPIコールをどこで行うことができますか?

基本的に、以下のようなReactクラスコンポーネントのcomponentDidMount()ライフサイクルメソッドでAPI呼び出しを行います

     componentDidMount(){
          //Here we do API call and do setState accordingly
     }

しかし、フックがReact v16.7.0に導入された後、ほとんどすべての機能コンポーネントが似ています

私のクエリは、フックを使用して機能コンポーネントでAPI呼び出しを行う必要があるのはどこですか?

componentDidMount()のような同様のメソッドはありますか?

24
Hemadri Dasari

はい、フック付きのcomponentDidMountに似た(しかし同じではありません!)代替があり、それはuseEffectフックです。

他の回答は、API呼び出しを行うことができる場所についての質問には実際には答えません。 useEffectおよび2番目の引数として空の配列またはオブジェクトを渡すcomponentDidMount()の代わりとして使用して、API呼び出しを行うことができます。ここでのキーは2番目の引数です。 2番目の引数として空の配列またはオブジェクトを指定しない場合、API呼び出しはすべてのレンダリングで呼び出され、事実上componentDidUpdateになります。

ドキュメントで述べたように:

入力の空の配列[]を渡すと、Reactに、エフェクトがコンポーネントの値に依存しないため、マウント時にのみエフェクトが実行され、アンマウント時にクリーンアップされることがわかります。アップデートでは実行されません。

API呼び出しを行う必要があるシナリオの例を次に示します。

マウント時の厳密なAPI呼び出し

以下のコードを実行して、結果を確認してください。

function User() {
  const [firstName, setFirstName] = React.useState(null);
  const [lastName, setLastName] = React.useState(null);
  
  React.useEffect(() => {
    fetch('https://randomuser.me/api/')
      .then(results => results.json())
      .then(data => {
        const {name} = data.results[0];
        setFirstName(name.first);
        setLastName(name.last);
      });
  }, []); // <-- Have to pass in [] here!

  return (
    <div>
      Name: {!firstName || !lastName ? 'Loading...' : `${firstName} ${lastName}`}
    </div>
  );
}

ReactDOM.render(<User />, document.querySelector('#app'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

いくつかのプロップ/ステートの変更時のAPIコール

たとえば、各ページにuserID state/propがあるユーザーのプロファイルページを表示する場合は、その変数を値としてuseEffectの2番目のパラメーターに渡し、新しいユーザーIDのデータが再取得されるようにする必要があります。 componentDidMountは、ユーザーAからユーザーBのプロファイルに直接移動する場合、コンポーネントを再マウントする必要がないため、ここでは不十分です。

従来のクラスの方法では、次のことを行います。

componentDidMount() {
  this.fetchData();
}

componentDidUpdate(prevProps, prevState) {
  if (prevState.id !== this.state.id) {
    this.fetchData();
  }
}

フックを使用すると、次のようになります。

useEffect(() => {
  this.fetchData();
}, [id]);

以下のコードを実行して、結果を確認してください。たとえば、idを2に変更して、useEffectが再度実行されることを確認します。

function Todo() {
  const [todo, setTodo] = React.useState(null);
  const [id, setId] = React.useState(1);
  
  React.useEffect(() => {
    if (id == null || id === '') {
      return;
    }
    
    fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
      .then(results => results.json())
      .then(data => {
        setTodo(data);
      });
  }, [id]); // useEffect will trigger whenever id is different.

  return (
    <div>
      <input value={id} onChange={e => setId(e.target.value)}/>
      <br/>
      <pre>{JSON.stringify(todo, null, 2)}</pre>
    </div>
  );
}

ReactDOM.render(<Todo />, document.querySelector('#app'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>

<div id="app"></div>

useEffect を読んで、それで何ができる/できないのかを知る必要があります。

サスペンス

Dan Abramovが このGitHubの問題 で述べたように:

長期的には、競合状態を助長するため、この(useEffect)パターンを推奨しません。など-通話の開始と終了の間に何が発生する可能性があり、新しい小道具を手に入れることができました。代わりに、データの取得にはSuspenseをお勧めします

サスペンスにご期待ください!

42
Yangshun Tay

次のようなフックを提供するライブラリを使用できます https://resthooks.io

その後、データの取得は次のように簡単になります。

const article = useResource(ArticleResource.detailShape(), { id });

これで、IDで記事を取得しました。不幸なパス(読み込み、エラー状態)はすべて、サスペンスと エラー境界 によってそれぞれ処理されます。

開始するには、次の簡単なガイドに従ってください。 https://resthooks.io/docs/getting-started/installation

わずか7kbのgzip圧縮で、これにより多くの苦痛が軽減され、長期的にはコードの繰り返しが少なくなるため、バンドルサイズが小さくなります。

2

use-http のように使用することもできます:

import useFetch from 'use-http'

function App() {
  // add whatever other options you would add to `fetch` such as headers
  const options = {
    method: 'POST',
    body: {}, // whatever data you want to send
  }

  var [data, loading, error] = useFetch('https://example.com', options)

  // want to use object destructuring? You can do that too
  var { data, loading, error } = useFetch('https://example.com', options)

  if (error) {
    return 'Error!'
  }

  if (loading) {
    return 'Loading!'
  }

  return (
    <code>
      <pre>{data}</pre>
    </code>
  )
}
0
Alex Cory

フックAPIで機能コンポーネントを使用している場合、useEffect()メソッドを使用して副作用を生成できます。これらの副作用のために状態が更新されるたびに、コンポーネントは再レンダリングされます。

ドキュメントの例。

import { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

たとえば、非同期要求のコールバック関数でsetCountを呼び出すことができます。コールバックが実行されると、状態が更新され、Reactがコンポーネントを再レンダリングします。また、ドキュメントから:

ヒント

Reactクラスのライフサイクルメソッドに精通している場合、useEffectフックはcomponentDidMountcomponentDidUpdate、およびcomponentWillUnmountの組み合わせと考えることができます。

0
Donny Verduijn