Fbsdkを使用して、ajaxリクエストでユーザーの詳細を取得しています。したがって、これをreduxで観察可能な叙事詩で行うのは理にかなっています。 fbsdkリクエストの方法では、.map()
と.catch()
を持たず、成功と失敗のコールバックを受け取ります。
コード:
export const fetchUserDetailsEpic: Epic<*, *, *> = (
action$: ActionsObservable<*>,
store
): Observable<CategoryAction> =>
action$.ofType(FETCH_USER_DETAILS).mergeMap(() => {
getDetails(store)
})
const getDetails = store => {
console.log(store)
let req = new GraphRequest(
'/me',
{
httpMethod: 'GET',
version: 'v2.5',
parameters: {
fields: {
string: 'email,first_name,last_name'
}
}
},
(err, res) => {
if (err) {
store.dispatch(fetchUserDetailsRejected(err))
} else {
store.dispatch(fetchUserDetailsFulfilled(res))
}
}
)
return new GraphRequestManager().addRequest(req).start()
}
エラーが発生します:
TypeError:ストリームが予想される場所に「未定義」を指定しました。 Observable、Promise、Array、またはIterableを提供できます。
このエラーがなくなるように、エピックからオブザーバブルを返すにはどうすればよいですか?
これからbindCallback
を試みる SOの答え :
const getDetails = (callBack, details) => {
let req = new GraphRequest(
'/me',
{
httpMethod: 'GET',
version: 'v2.5',
parameters: {
fields: {
string: 'email,first_name,last_name'
}
}
},
callBack(details)
)
new GraphRequestManager().addRequest(req).start()
}
const someFunction = (options, cb) => {
if (typeof options === 'function') {
cb = options
options = null
}
getDetails(cb, null)
}
const getDetailsObservable = Observable.bindCallback(someFunction)
export const fetchUserDetailsEpic: Epic<*, *, *> = (
action$: ActionsObservable<*>
): Observable<CategoryAction> =>
action$.ofType(FETCH_USER_DETAILS).mergeMap(() => {
getDetailsObservable()
.mergeMap(details => {
return Observable.of(fetchUserDetailsFulfilled(details))
})
.catch(error => Observable.of(fetchUserDetailsRejected(error)))
})
同じエラーを取得する
start(timeout: ?number) {
const that = this;
const callback = (error, result, response) => {
if (response) {
that.requestCallbacks.forEach((innerCallback, index, array) => {
if (innerCallback) {
innerCallback(response[index][0], response[index][1]);
}
});
}
if (that.batchCallback) {
that.batchCallback(error, result);
}
};
NativeGraphRequestManager.start(this.requestBatch, timeout || 0, callback);
}
ご覧のとおり、何も返されないので、事実上undefined
です。 Rx mergeMap
には、Observableまたはそれに互換性のあるインスタンスが必要です( 詳細 )。
さらにアクションをディスパッチするため、元のコードを次のように変更できます。
export const fetchUserDetailsEpic: Epic<*, *, *> = (
action$: ActionsObservable<*>,
store
): Observable<CategoryAction> =>
action$.ofType(FETCH_USER_DETAILS).do(() => { // .mergeMap changed to .do
getDetails(store)
})
const getDetails = store => {
console.log(store)
let req = new GraphRequest(
'/me',
{
httpMethod: 'GET',
version: 'v2.5',
parameters: {
fields: {
string: 'email,first_name,last_name'
}
}
},
(err, res) => {
if (err) {
store.dispatch(fetchUserDetailsRejected(err))
} else {
store.dispatch(fetchUserDetailsFulfilled(res))
}
}
)
return new GraphRequestManager().addRequest(req).start()
}
正直なところ、私はあなたの2回目の試みが少し良い/少ない結合を見つけます。動作させるには、次のようなことができます。
const getDetails = Observable.create((observer) => {
let req = new GraphRequest(
'/me',
{
httpMethod: 'GET',
version: 'v2.5',
parameters: {
fields: {
string: 'email,first_name,last_name'
}
}
},
(error, details) => {
if (error) {
observer.error(error)
} else {
observer.next(details)
observer.complete()
}
}
)
new GraphRequestManager().addRequest(req).start()
})
export const fetchUserDetailsEpic: Epic<*, *, *> = (
action$: ActionsObservable<*>
): Observable<CategoryAction> =>
action$.ofType(FETCH_USER_DETAILS).mergeMap(() => {
getDetails()
.map(details => fetchUserDetailsFulfilled(details)) // regular .map should be enough here
.catch(error => Observable.of(fetchUserDetailsRejected(error)))
})
@artur grzesiakには正しい答えがあるように見えますが、完全を期すためにbindCallback
を使用できると思います。
Arturの答えで私が抱えている唯一の問題は、fetchUserDetailsRejected
がエラー処理アクションであるため、エピックでエラーをキャッチする必要がないと思うことです(おそらく、reducerは適切に処理します)。
このリファレンスを使用しました RxJs Static Public Methods:bindCallback
タイプf(x、callback)の関数fを与えると、g(x)として呼び出されるとObservableを出力する関数gを返します。
// This callback receives the results and returns one or other action (non-observable)
const callback = (err, res) => {
return err
? fetchUserDetailsRejected(err)
: fetchUserDetailsFulfilled(res)
}
// Here is the graph request uncluttered by concerns about the epic
const getDetails = (store, callback) => {
console.log(store)
let req = new GraphRequest(
'/me',
{
httpMethod: 'GET',
version: 'v2.5',
parameters: {
fields: {
string: 'email,first_name,last_name'
}
}
},
callback
)
new GraphRequestManager().addRequest(req).start()
}
// This bound function wraps the action returned from callback in an Observable
const getDetails$ = Observable.bindCallback(getDetails).take(1)
// The epic definition using bound callback to return an Observable action
export const fetchUserDetailsEpic: Epic<*, *, *> =
(action$: ActionsObservable<*>, store): Observable<CategoryAction> =>
action$.ofType(FETCH_USER_DETAILS).mergeMap(() => getDetails$(store))
どのように働いていたかよく覚えていないredux-observable
使用前RxJS >= 6
しかし、私は助けようとします;)
まず、自分自身を派遣する必要はありません。redux-observableが自動的に行います。 この記事では 、彼らはそれが内部でどのように機能するかを示しているので、彼らはディスパッチを呼び出しますが、あなたはする必要はありません。新しい実装では、store
ストリームを優先して、2番目の引数としてstate
を削除しました。
const epic = (action$, store) => { ... //before
const epic = (action$, state$) => { ... //after
しかし、最も重要なのは、発生する問題は、一連のアクションではなく、単一の(ディスパッチされた)アクションを返すことです。 彼らのウェブサイトから :
アクションのストリームを取得し、アクションのストリームを返す関数です。
簡単な解決策は、コールバックからオブザーバブルを返すことだと思います。
(err, res) => {
if (err) {
return Observable.of(fetchUserDetailsRejected(err))
}
return Observable.of(fetchUserDetailsFulfilled(res))
}
コメントに基づいて回答を更新します。幸運を!
これがundefined
の考えられる理由と思われます。 undefined
コールバックでmergeMap
を返しています。
この
action$.ofType(FETCH_USER_DETAILS).mergeMap(() => {
getDetails(store)
})
どちらかでなければなりません
action$.ofType(FETCH_USER_DETAILS).mergeMap(() => getDetails(store))
または
action$.ofType(FETCH_USER_DETAILS).mergeMap(() => {
return getDetails(store)
})