質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

2回答

689閲覧

Reactでfetchの順番を制御したい

dfsgerehs

総合スコア4

Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2024/08/12 04:20

実現したいこと

typescriptで複数のfetchの処理の順番を変えたいです。

発生している問題・分からないこと

fetchでデータを2回取得して表示を行うコンポーネントを用意します。このコンポーネントを複数実装すると2回目のfetchは全てのコンポーネントの1回目のfetchが終わらないと実行されません。この順番を変更して「1回目のfetch→別コンポーネントの1回目のfetch」ではなく「1回目のfetch→2回目のfetch→別コンポーネントの1回目のfetch」と割り込ませる方法はないでしょうか?

該当のソースコード

typescript

1'use client' 2import { useEffect, useState } from "react"; 3 4export default function ComponentC() { 5 const [data, setData] = useState<string | null>(null); 6 useEffect(() => { 7 const fetchData = async () => { 8 const url = `api/componentA`; //返答に3秒かかるAPI 9 const response = await fetch(`${url}`, { 10 method: 'POST', 11 headers: { 12 'Content-Type': 'application/json', 13 }, 14 body: JSON.stringify({ URL: url }), // URLをリクエストボディに含める 15 }); 16 setData("componentAから取得"); 17 const url2 = `api/componentB`; //返答に3秒かかるAPI 18 const response2 = await fetch(`${url2}`, { 19 method: 'POST', 20 headers: { 21 'Content-Type': 'application/json', 22 }, 23 body: JSON.stringify({ URL: url }), // URLをリクエストボディに含める 24 }); 25 setData("componentBから取得"); 26 }; 27 fetchData(); 28 }, []); 29 30 return ( 31 <> 32 <div>div{data}</div> 33 </> 34 ); 35 36}

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

「typescript fetch 順番」などで調べた結果、fetchで実行したい関数を配列に入れて制御する方法が見つかりました。しかしこの方法だと配列の中のどのfetchを優先して実行するかの処理に加えて排他的制御が必要なので少し手間になると考えました。コンポーネントの描画順でfetchを優先する方法などはないでしょうか?

補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2024/08/12 04:53

なぜ順番を変えたいのでしょうか?
dfsgerehs

2024/08/12 05:14

このコードでは分かりにくいのですが、2つのfetchが終了したらUIを表示するといった動作を将来的には行いたいです。このコンポーネントを100個くらい作成した時、処理時間は同じでもUIをなるべく早く表示したいため順番の制御を行いたいです。
adihs2

2024/08/12 13:40

質問に > このコンポーネントを複数実装すると とありますがその実装とは具体的にはComponentCの一覧をイメージすればよいですか? こんなようなものとか: <div> {arrayC.map(c => <ComponentC key={i} />)} </div>
dfsgerehs

2024/08/12 21:24

そのようなイメージです
guest

回答2

0

ベストアンサー

複数のComponentCを子コンポーネントとして持つコンテナコンポーネント側で

コンポーネントの描画順でfetchを優先する

という制御を行えばよいかと思いました。一案としてはたとえばこういう感じです。

まず ComponentC に prop fetchingonFetchingComplete を追加してこのように修正:

diff

1-'use client' 2 import { useEffect, useState } from "react"; 3 4-export default function ComponentC() { 5+export default function ComponentC({ 6+ fetching, 7+ onFetchingComplete 8+}: { 9+ fetching: boolean 10+ onFetchingComplete: () => void 11+}) { 12 const [data, setData] = useState<string | null>(null); 13 useEffect(() => { 14+ if (!fetching) return 15+ 16 const fetchData = async () => { 17 const url = `api/componentA`; //返答に3秒かかるAPI 18 const response = await fetch(`${url}`, { 19@@ -24,8 +31,8 @@ export default function ComponentC() { 20 }); 21 setData("componentBから取得"); 22 }; 23- fetchData(); 24- }, []); 25+ fetchData().then(onFetchingComplete) 26+ }, [fetching, onFetchingComplete]); 27 28 return ( 29 <>

そしてコンテナ側の実装例は下記です。

typescript

1'use client' 2import ComponentC from "@/components/ComponentC"; 3import { useState } from "react"; 4 5export default function ContainerPage() { 6 const [fetchingIndex, setFetchingIndex] = useState(0); 7 8 return ( 9 <div> 10 {[...Array(5)].map((_, i) => ( 11 <ComponentC 12 key={i} 13 fetching={fetchingIndex === i} 14 onFetchingComplete={() => setFetchingIndex(i + 1)} 15 /> 16 ))} 17 </div> 18 ); 19} 20

投稿2024/08/12 18:01

adihs2

総合スコア12

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dfsgerehs

2024/08/13 01:19

この方法で実現ができました。ありがとうございます。
guest

0

もしあなたがfetchに時間がかかることを理解していて、かつその二つの処理がなんの関連性もなくawaitする意味がないことを理解しているのであれば、以下のようにすべきでしょう。

javascript

1async function fetchData() { 2 Promise.all([ 3 fetch(`${url}`, { 4 method: 'POST', 5 headers: { 6 'Content-Type': 'application/json', 7 }, 8 body: JSON.stringify({ URL: url }), // URLをリクエストボディに含める 9 }), 10 fetch(`${url2}`, { 11 method: 'POST', 12 headers: { 13 'Content-Type': 'application/json', 14 }, 15 body: JSON.stringify({ URL: url }), // URLをリクエストボディに含める 16 }) 17 ]) 18 .then(([response, response2]) => { 19 setData("componentAから取得"); 20 setData("componentBから取得"); 21 return [response, response2] 22 }) 23 // TODOエラー処理 24 .catch(error => console.error('Error:', error)); 25};

要点を書きだすと以下のようなコードになるでしょう。

javascript

1async function fetchData() { 2 Promise.all([ 3 fetch(`${url}`), 4 fetch(`${url2}`) 5 ]) 6 .then(([response, response2]) => { 7 setData("componentAから取得"); 8 setData("componentBから取得"); 9 return [response, response2] 10 }) 11 // TODOエラー処理 12 .catch(error => console.error('Error:', error)); 13};

Promise.allは配列で与えられたPromise(コードでいうとfetch)をすべて処理しますが、これは非同期的に行われるため、両方が同時に行われ、遅いほうの処理を待ちます。
.thenについてはfetch(Promise)を処理する方法と同じです。
また、このコードはおそらくPromisのresponsを処理するのが一般的であるため以下のようにも書けます。(jsonとして取得する場合。textを使う場合はjson()ではなくtext()を使用する)

javascript

1async function fetchData() { 2 Promise.all([ 3 fetch(`${url}`).then(response => response.json()), 4 fetch(`${url2}`).then(response => response.json()) 5 ]) 6 .then(([response, response2]) => { 7 return [response, response2] 8 }) 9 // TODOエラー処理 10 .catch(error => console.error('Error:', error)); 11};

以上の内容で、質問で行いたいことは解決しますでしょうか?

もし、100回同じコードを記述しないといけないのであれば以下のように記述できるかもしれません。

javascript

1async function fetchData() { 2 urls.push(url) 3 urls.push(url2) 4 5 Promise.all(urls.map(url => fetch(url))) 6 .then(dataArray => { 7 console.log(dataArray); 8 }) 9 // TODOエラー処理 10 .catch(error => console.error('Error:', error)); 11};

参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

補足
私はバニラjsの知識で回答していますので、Reactで不備があったり一般的なアプローチではないかもしれません。

投稿2024/08/12 15:49

utm.

総合スコア784

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dfsgerehs

2024/08/12 21:36

この方法では実現が難しいようです。原因は、私の質問内容が不十分だったためです。申し訳ありません。APIの返答には別のURLが含まれており、このURLで2回目のfetchを行うという処理のため、この方法では対応できません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問