如何使用 RxJS 发出多个 HTTP 请求并将响应合并到一个有效负载并将其映射到另一个操作?
How to make multiple HTTP requests with RxJS and merge the response into one payload and map it to another action?
根据标题,我一直在尝试找出一种方法,从一个动作有效负载进行多个 HTTP 调用,基本上将所有结果合并到一个数组中,然后将结果作为有效负载映射到另一个动作。
这是我现有的代码,它可以工作,但它似乎没有合并两个响应,只关心请求响应的最后一个响应,也许我使用了错误的运算符,我只是选择了 RxJS 和尝试不同的东西来学习,希望有人能够解释我哪里出错了。
非常感谢任何帮助或指导。
{
type: 'FETCH_DATA',
payload: {
key: 'standings',
value: [
'http://url-1',
'http://url-2'
],
})
}
// The epic is listening to the above action
const fetchDataEpic = action$ => action$.pipe(
ofType('FETCH_DATA'),
mergeMap(action => {
const { key, value } = action.payload;
if (Array.isArray(value) && value.length) {
const makeRequest = value.map((x, i) => ajax.getJSON(value[i]))
return (
forkJoin(
makeRequest,
response => {
return ({
type: 'FETCH_DATA_SUCCEEDED',
payload: {
key,
value: response,
},
})
}
)
)
}
})
);
注意:两个请求的响应采用相同的 JSON 格式,具有相同的属性,但数据不同。
提前致谢
看起来您正在使用 rxjs 的 ajax 函数,它应该已经为您提供了可观察值。在这种情况下,一旦所有可观察对象都发出了值,forkJoin 应该将这两个值作为数组提供给您。然后您可以使用 map 函数将其添加到您的操作负载中。
const requestArrays = [1, 2].map(i => {
return rxjs.ajax.ajax.getJSON(`https://jsonplaceholder.typicode.com/posts/${i}`);
});
rxjs.forkJoin(requestArrays)
.pipe(
rxjs.operators.tap(resp => {
console.log('Part 1: Response so far: ');
console.log(resp);
}),
rxjs.operators.map(value => {
return {
type: 'FETCH_DATA_SUCCEEDED',
payload: {
value
}
};
}),
rxjs.operators.tap(resp => {
console.log('Part 2: Result as a action payload: ');
console.log(resp);
}),
)
.subscribe();
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js"></script>
编辑:
以下是您将如何实施它的大致方法。
const action = {
type: 'FETCH_DATA',
payload: {
value: [
'1',
'2'
],
}
};
rxjs.of(action)
.pipe(
rxjs.operators.mergeMap(action => {
const requestArrays = action.payload.value.map(i => {
return rxjs.ajax.ajax.getJSON(`https://jsonplaceholder.typicode.com/posts/${i}`);
});
return rxjs.forkJoin(requestArrays)
.pipe(
rxjs.operators.map(value => {
return {type: 'FETCH_DATA_SUCCEEDED', payload: {value}};
})
)
})
)
.subscribe(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js"></script>
我不认为它只关心 last 响应,而是 first 响应。
那是因为如果你想自定义来自forkJoin
的响应,第二个(或最后一个,如果第一个不是数组)参数(这是一个函数)接受多个参数,它们是所提供请求的响应。
因此,这是我为了获得整个响应数组而执行的更改。
/* ... */
forkJoin(
makeRequest,
(...response) => {
return ({
type: 'FETCH_DATA_SUCCEEDED',
payload: {
key,
value: response,
},
})
}
)
/*
编辑:将合并的响应发送到另一个操作
这可以通过使用 tap 运算符来实现,它通常在您必须处理副作用时使用。
(
mergeMap(action => { ... }),
tap(action => sendToOtherAction(action))
)
根据标题,我一直在尝试找出一种方法,从一个动作有效负载进行多个 HTTP 调用,基本上将所有结果合并到一个数组中,然后将结果作为有效负载映射到另一个动作。
这是我现有的代码,它可以工作,但它似乎没有合并两个响应,只关心请求响应的最后一个响应,也许我使用了错误的运算符,我只是选择了 RxJS 和尝试不同的东西来学习,希望有人能够解释我哪里出错了。
非常感谢任何帮助或指导。
{
type: 'FETCH_DATA',
payload: {
key: 'standings',
value: [
'http://url-1',
'http://url-2'
],
})
}
// The epic is listening to the above action
const fetchDataEpic = action$ => action$.pipe(
ofType('FETCH_DATA'),
mergeMap(action => {
const { key, value } = action.payload;
if (Array.isArray(value) && value.length) {
const makeRequest = value.map((x, i) => ajax.getJSON(value[i]))
return (
forkJoin(
makeRequest,
response => {
return ({
type: 'FETCH_DATA_SUCCEEDED',
payload: {
key,
value: response,
},
})
}
)
)
}
})
);
注意:两个请求的响应采用相同的 JSON 格式,具有相同的属性,但数据不同。
提前致谢
看起来您正在使用 rxjs 的 ajax 函数,它应该已经为您提供了可观察值。在这种情况下,一旦所有可观察对象都发出了值,forkJoin 应该将这两个值作为数组提供给您。然后您可以使用 map 函数将其添加到您的操作负载中。
const requestArrays = [1, 2].map(i => {
return rxjs.ajax.ajax.getJSON(`https://jsonplaceholder.typicode.com/posts/${i}`);
});
rxjs.forkJoin(requestArrays)
.pipe(
rxjs.operators.tap(resp => {
console.log('Part 1: Response so far: ');
console.log(resp);
}),
rxjs.operators.map(value => {
return {
type: 'FETCH_DATA_SUCCEEDED',
payload: {
value
}
};
}),
rxjs.operators.tap(resp => {
console.log('Part 2: Result as a action payload: ');
console.log(resp);
}),
)
.subscribe();
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js"></script>
编辑: 以下是您将如何实施它的大致方法。
const action = {
type: 'FETCH_DATA',
payload: {
value: [
'1',
'2'
],
}
};
rxjs.of(action)
.pipe(
rxjs.operators.mergeMap(action => {
const requestArrays = action.payload.value.map(i => {
return rxjs.ajax.ajax.getJSON(`https://jsonplaceholder.typicode.com/posts/${i}`);
});
return rxjs.forkJoin(requestArrays)
.pipe(
rxjs.operators.map(value => {
return {type: 'FETCH_DATA_SUCCEEDED', payload: {value}};
})
)
})
)
.subscribe(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.min.js"></script>
我不认为它只关心 last 响应,而是 first 响应。
那是因为如果你想自定义来自forkJoin
的响应,第二个(或最后一个,如果第一个不是数组)参数(这是一个函数)接受多个参数,它们是所提供请求的响应。
因此,这是我为了获得整个响应数组而执行的更改。
/* ... */
forkJoin(
makeRequest,
(...response) => {
return ({
type: 'FETCH_DATA_SUCCEEDED',
payload: {
key,
value: response,
},
})
}
)
/*
编辑:将合并的响应发送到另一个操作
这可以通过使用 tap 运算符来实现,它通常在您必须处理副作用时使用。
(
mergeMap(action => { ... }),
tap(action => sendToOtherAction(action))
)