基本的に、以下のようなReactクラスコンポーネントのcomponentDidMount()
ライフサイクルメソッドでAPI呼び出しを行います
componentDidMount(){
//Here we do API call and do setState accordingly
}
しかし、フックがReact v16.7.0に導入された後、ほとんどすべての機能コンポーネントが似ています
私のクエリは、フックを使用して機能コンポーネントでAPI呼び出しを行う必要があるのはどこですか?
componentDidMount()
のような同様のメソッドはありますか?
はい、フック付きのcomponentDidMount
に似た(しかし同じではありません!)代替があり、それはuseEffect
フックです。
他の回答は、API呼び出しを行うことができる場所についての質問には実際には答えません。 useEffect
および2番目の引数として空の配列またはオブジェクトを渡すをcomponentDidMount()
の代わりとして使用して、API呼び出しを行うことができます。ここでのキーは2番目の引数です。 2番目の引数として空の配列またはオブジェクトを指定しない場合、API呼び出しはすべてのレンダリングで呼び出され、事実上componentDidUpdate
になります。
ドキュメントで述べたように:
入力の空の配列[]を渡すと、Reactに、エフェクトがコンポーネントの値に依存しないため、マウント時にのみエフェクトが実行され、アンマウント時にクリーンアップされることがわかります。アップデートでは実行されません。
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>
たとえば、各ページに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をお勧めします
サスペンスにご期待ください!
次のようなフックを提供するライブラリを使用できます https://resthooks.io
その後、データの取得は次のように簡単になります。
const article = useResource(ArticleResource.detailShape(), { id });
これで、IDで記事を取得しました。不幸なパス(読み込み、エラー状態)はすべて、サスペンスと エラー境界 によってそれぞれ処理されます。
開始するには、次の簡単なガイドに従ってください。 https://resthooks.io/docs/getting-started/installation
わずか7kbのgzip圧縮で、これにより多くの苦痛が軽減され、長期的にはコードの繰り返しが少なくなるため、バンドルサイズが小さくなります。
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>
)
}
フック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フックは
componentDidMount
、componentDidUpdate
、およびcomponentWillUnmount
の組み合わせと考えることができます。