Redux: 複数の非同期呼び出しを待つためのreduxイディオムは何ですか?

作成日 2015年09月14日  ·  30コメント  ·  ソース: reduxjs/redux

反応コンポーネントを開始するとき、2つの異なる非同期http呼び出しを行い、その結果を待つ必要があります。
これらの2つの呼び出しは、理想的には2つの異なるレデューサーにデータを配置します。

単一の非同期呼び出しを行うためのパターンを理解しています。
ただし、複数の非同期呼び出しを実行し、それらを並行して実行し、結果が到着するのを_両方_待つための適切なサンプルは見当たりません。

これを行うための冗長な方法は何ですか?

question

最も参考になるコメント

ReduxThunkミドルウェアを使用していることを前提としています。

アクションクリエーターを宣言します。

import 'babel-core/polyfill'; // so I can use Promises
import fetch from 'isomorphic-fetch'; // so I can use fetch()

function doSomething() {
  return dispatch => 
    fetch(
      '/api/something'
    ).then(
      response => response.json()
    ).then(
      json => dispatch({ type: DO_SOMETHING, json }),
      err => dispatch({ type: SOMETHING_FAILED, err })
    );
}

function doSomethingElse() {
  return dispatch => 
    fetch(
      '/api/something'
    ).then(
      response => response.json()
    ).then(
      json => dispatch({ type: DO_SOMETHING_ELSE, json }),
      err => dispatch({ type: SOMETHING_ELSE_FAILED, err })
    );
}

チェーンをサンクアクションクリエーター内の関数の戻り値として保持することにより、最後にPromiseを返すようにする方法に注意してください。 これは私にそれをさせます:

store.dispatch(doSomething()).then(() => {
  console.log('I did something');
});

Redux Thunkを使用すると、 dispatchは、サンクアクションの作成者(この場合はPromise)から返した関数の戻り値を返します。

これにより、 Promise.all()ようなコンビネータを使用して、いくつかのアクションの完了を待つことができます。

Promise.all([
  store.dispatch(doSomething()),
  store.dispatch(doSomethingElse())
]).then(() => {
  console.log('I did everything!');
});

ただし、前のアクションクリエーターの_構成_として機能する別のアクションクリエーターを定義し、内部でPromise.allを使用することをお勧めします。

function doEverything() {
  return dispatch => Promise.all([
    dispatch(doSomething()),
    dispatch(doSomethingElse())
  ]);
}

今、あなたはただ書くことができます

store.dispatch(doEverything()).then(() => {
  console.log('I did everything!');
});

ハッピーディスパッチ!

全てのコメント30件

ReduxThunkミドルウェアを使用していることを前提としています。

アクションクリエーターを宣言します。

import 'babel-core/polyfill'; // so I can use Promises
import fetch from 'isomorphic-fetch'; // so I can use fetch()

function doSomething() {
  return dispatch => 
    fetch(
      '/api/something'
    ).then(
      response => response.json()
    ).then(
      json => dispatch({ type: DO_SOMETHING, json }),
      err => dispatch({ type: SOMETHING_FAILED, err })
    );
}

function doSomethingElse() {
  return dispatch => 
    fetch(
      '/api/something'
    ).then(
      response => response.json()
    ).then(
      json => dispatch({ type: DO_SOMETHING_ELSE, json }),
      err => dispatch({ type: SOMETHING_ELSE_FAILED, err })
    );
}

チェーンをサンクアクションクリエーター内の関数の戻り値として保持することにより、最後にPromiseを返すようにする方法に注意してください。 これは私にそれをさせます:

store.dispatch(doSomething()).then(() => {
  console.log('I did something');
});

Redux Thunkを使用すると、 dispatchは、サンクアクションの作成者(この場合はPromise)から返した関数の戻り値を返します。

これにより、 Promise.all()ようなコンビネータを使用して、いくつかのアクションの完了を待つことができます。

Promise.all([
  store.dispatch(doSomething()),
  store.dispatch(doSomethingElse())
]).then(() => {
  console.log('I did everything!');
});

ただし、前のアクションクリエーターの_構成_として機能する別のアクションクリエーターを定義し、内部でPromise.allを使用することをお勧めします。

function doEverything() {
  return dispatch => Promise.all([
    dispatch(doSomething()),
    dispatch(doSomethingElse())
  ]);
}

今、あなたはただ書くことができます

store.dispatch(doEverything()).then(() => {
  console.log('I did everything!');
});

ハッピーディスパッチ!

@gaearon promiseミドルウェアよりもthunkを好む特別な理由はありますか? または何をいつ使用するかについてのアドバイス? ありがとう。

特別な理由はありませんが、私はそれをよく知っています。
両方を試して、自分に最適なものを使用してください。

わかった、ありがとう!

JFYI :)
screen shot 2015-09-14 at 11 06 42 am

@gaearon簡単な質問-上記の例を見てください。

store.dispatch(doSomething()).then(() => {
  console.log('I did something');
});

doSomething拒否された場合でも、「I didsomething」ブロックがヒットするようです-キャッチした後にdoSomethingチェーンのエラーを再スローしていないためです。 それは意図的なものですか? そうでない場合、そして代わりにエラーを再スローする場合は、呼び出し元で再度処理しますか?

これは単なる例であり、これを見る方法として、これが決定的な参照であるという意味ではありません。 私はそれに少しの本当の考えを与えませんでした。

アクションクリエーターからの約束を返す方法を知っています。残りはあなた次第です。 エラーを再スローするかどうか、どこで処理するかは、すべてあなた次第です。 これは実際にはReduxの懸念事項ではないので、私のアドバイスは他の誰よりも優れています。この場合、構築したいものと好みのスタイルについて、これまで以上に多くのコンテキストがあります。

かっこいい、ありがとう! それが事実だと考えましたが、私が見落としていた魔法がないことを確認したかったのです。

Reduxはカスタマイズ可能であるため、 dispatch戻り値が期待どおりになるとは限りません。

実際、私はredux-loopを取っているので、実生活で1つの問題に遭遇しました。 dispatchを調整して、ラップされたPromise(https://github.com/raisemarketplace/redux-loop/blob/master/modules/effects.js#L38)を返します。 したがって、 dispatch戻り値に依存することはできません。

さて、ダンがこのスレッドで上で述べたように、それは_your_アプリであり、_you_はあなたのアクションクリエーターを書いているので、_you_は彼らが何を返すかを決めることができます。

@markerikson dispatch戻り値は、ミドルウェアが微調整する可能性があるため、アクション作成者の戻り値であるとは限りません。

しかし、回避策があります。 dispatch(actonCreator())thenをチェーンする代わりに、 actionCreator()チェーンすることができます。

はい、ミドルウェアは物事を微調整することができますが、私のポイントは、_あなた_があなた自身のアプリでミドルウェアをセットアップしているということです:)

こんにちは@gaearon 、簡単な(うまくいけば関連する)質問! のようなことをすることについてのあなたの見解は何ですか

function fetchDataBWhichDependsOnA() {
  return dispatch => {
    dispatch(fetchDataA())
      .then(() => {
        fetch('/api/get/data/B')
          .then(dispatch(receiveDataB(response.data)))
      })
  }
}

このコードスニペットには2つのネストされた非同期アクションがあり、それらは機能しますが、テストに問題があります。 fetchDataA()は、非同期呼び出しのレベルが1つしかないため、テストできます。 しかし、 fetchDataBWhichDependsOnA()テストを作成しようとしたときに、 thenブロックのstoreから最新の値を取得できませんthen

@timothytongあなたは約束を返していません。 dispatchとネストされたfetch呼び出しから結果を返す場合、チェーン全体が解決されるまでテストを待つことができるはずです。

@johanneslumpe良いキャッチ、ありがとう仲間! 残っているのは、非同期フェッチチェーンでデータの依存関係を処理して、これが受け入れられるかどうかの問題だけです。

私も同じ問題を抱えていて、30分かけて解決策を考え出しました。 私はこの実装を完了していませんが、正しい方向に進んでいるように感じます。

https://github.com/Sailias/sync-thunk

私の考えでは、コンポーネントは特定のredux状態にデータを入力するように要求できます。そうでない場合は、マップを参照してアクションを呼び出してデータを入力し、 thenチェーンする必要があります。 チェーン内の各アクションは、渡されるデータを必要としません。依存するアクションがデータを入力するので、状態からデータを取得するだけです。

@gaearon

Promise.all([
  store.dispatch(doSomething()),
  store.dispatch(doSomethingElse())
]).then(() => {
  console.log('I did everything!');
});

これについて質問があります。 とても基本的なことならごめんなさい。

このシナリオでは、2つのディスパッチがあります。 つまり、コンポーネントが2回レンダリングされます。 しかし、コンポーネントが両方のデータに何か意味のあるものを表示させたい場合はどうでしょうか。

したがって、そのシナリオでは、コンポーネントを1回だけレンダリングし、それですべての非同期アクションが完了します。

redux-batched-subscriberedux-batched-actionsのように、この問題を処理しているように見えるいくつかのミドルウェアの名前を取得しました。 しかし、最善のアプローチについては少し混乱しています。

これが有効なシナリオである場合、これを処理するための推奨されるアプローチは何でしょうか。

@jintoppyコンポーネントをレンダリングするための複数の呼び出しを回避することが求められている場合、 Promise.allソリューションは役に立ちません。 なぜなら、両方のdoSomething() and doSomething() 、状態の変化を引き起こし、コンポーネントのレンダリングを引き起こすすべてのディスパッチデータです。

@jintoppyなぜあなたはあなたの状況を処理するためにmiddlwaresが必要なのですか?
あなたがそのようなsmthをするのを妨げるものは何ですか。

// action creator
function fetchAB() {
  return dispatch => {
    const fetchA = fetch( 'api/endpoint/A' );
    const fetchB = fetch( 'api/endpoint/B' );
    return Promise.all([ fetchA, fetchB ])
      .then( values => dispatch(showABAction(values)) )
      .catch( err => throw err );
  }
} 

すべてのリクエストを1つのアクション作成者に入れて、すべてが解決されたときにのみアクションのディスパッチを起動できます。 その場合、レデューサーが呼び出され、状態が1回だけ変更されるため、render()も1回だけ起動される可能性があります。

@apranovich :このアプローチには1つの問題があります。 ここで、1つのアクションで複数のフェッチを組み合わせる必要があります。 したがって、たとえば10回の非同期呼び出しがある場合は、それらすべてを1つのアクションにまとめる必要があります。 また、これらの10個の非同期呼び出しのうち1つを後でトリガーしたい場合はどうすればよいですか? このアプローチでは、基本的に、すべての非同期ロジックが1つのアクションに含まれます。

有益な情報をありがとうございました。 簡単な質問です。同じことをどのように実現できますか。代わりに、あるフェッチが次のフェッチメソッドに必要なデータを返す場合。 たとえば、地理位置を入力してID(最初のfetch )を取得する無料の天気APIエンドポイントがあります。これは、次のfetch場所の天気を取得するために必要です。 これは奇妙なユースケースであることは知っていますが、同様の状況を処理する方法を知りたいと思います。 前もって感謝します!

こんにちは@gaearon 、私は私のこの質問についてあなたのレビューを得たいと思います。 2つのAPIに対してネストされた非同期呼び出しを行う必要があります。 2番目のAPIからの応答は、最初のAPIの応答に依存しています。

export const getApi=()=>{
        return(d)=>{
        axios({
            method:'GET',
            url:Constants.URLConst+"/UserProfile",
            headers:Constants.headers
        }).then((response)=>{
            return d({
                type:GET_API_DATA,
                response,
                axios({
                    method:'GET',
                    url:Constants.URLConst+"/UserProfileImage?enterpriseId="+response.data.ProfileData.EnterpriseId,
                    headers:Constants.headers
                }).then((response1)=>{
                    return d({
                        type:GET_PROFILE_IMAGE,
                        response1
                    })
                })
            })
        }).catch((e)=>{
            console.log("e",e);
        })
    }

}

上記のようなことを試しましたが、これは機能しません。私のプロジェクトでは、両方のAPIからの応答を個別に使用する必要があります。
それで、それを行う正しい方法は何ですか?

ありがとう。

@ c0b41 、更新された質問を確認してください。

ちょっと@ c0b41 、これは2番目のaxios呼び出しで構文エラーを与えています。

@ aayushis12@ c0b41 :これはバグトラッカーであり、ヘルプフォーラムではありません。 StackOverflowまたはReactifluxでこの質問をしてみてください。 質問を見て助けてくれる人が増えるでしょう。

それを経験している人のために

私はすべてをしました

すべての非同期呼び出しが解決される前にが出力されます。非同期アクションの作成者からステートメントまたは式を返しているかどうかを確認してください。

たとえば、矢印関数でdoSomethingElse()が{}で宣言されている場合

function doSomethingElse() {
  return dispatch => {
    fetch(
      '/api/something'
    ).then(
      response => response.json()
    ).then(
      json => dispatch({ type: DO_SOMETHING_ELSE, json }),
      err => dispatch({ type: SOMETHING_ELSE_FAILED, err })
    );
  }
}

「私はすべてをやりました」はdoSomethingElse()解決する前に印刷されます。 =>後に{}をドロップして、これを解決します。

@gaearon https://github.com/reduxjs/redux/issues/723#issuecomment -139927639に基づく1つの質問2つのアクションがディスパッチされるのを待つアクションをディスパッチする必要がある場合、どのように処理しますか?それらの行動のために変わったのですか? アクションがディスパッチされたが、状態が変更される前にthen内のアクションが実行される場合があります。 redux-thunkを使用しています。

@enmanuelduran :ダンはもうアクティブなメンテナではありません-彼にpingを

コードを見ずに質問に答えるのは難しいですが、私たちの問題は実際にはディスカッションフォーラムを意図したものではありません。 Stack Overflowに質問を投稿すると、より良い回答が得られる可能性が高くなります。

@markeriksonああ、申し訳ありませんが、それは私の意図ではありませんでした、誰かが興味を持っている場合はstackoverflowで質問を作成しました: https

たくさんの人に感謝します。

このページは役に立ちましたか?
0 / 5 - 0 評価