如何在Cycle.js中顺序请求数据?
问题描述:
我是新来的反应式编程和around.js周围玩,试图实现谁跟随框this tutorial。但我明白,为了正确实施(和学习目的),我没有一个数据:完整的用户名。我可以通过依次获取用户,然后从服务器获取完整的用户数据来获取。在势在必行的风格,我会做这样的事情:如何在Cycle.js中顺序请求数据?
fetch(`https://api.github.com/users`)
.then(data => data.json())
.then(users => fetch(users[0].url))
.then(data => data.json())
.then(/* ... work with data ... */)
但我该怎么做在循环? 我使用获取驱动程序,并试图像这样:
function main({ DOM, HTTP }) {
const users = `https://api.github.com/users`;
const refresh$ = DOM.select(`.refresh`).events(`click`)
const response$ = getJSON({ key: `users` }, HTTP)
const userUrl$ = response$
.map(users => ({
url: R.prop(`url`, R.head(users)),
key: `user`,
}))
.startWith(null)
const request$ = refresh$
.startWith(`initial`)
.map(_ => ({
url: `${users}?since=${random(500)}`,
key: `users`,
}))
.merge(userUrl$)
const dom$ = ...
return {
DOM: dom$,
HTTP: request$,
};
}
其中getJSON
是
function getJSON(by, requests$) {
const type = capitalize(firstKey(by));
return requests$
[`by${type}`](firstVal(by))
.mergeAll()
.flatMap(res => res.json());
我总是得到一些神秘的(对我来说)错误,如:TypeError: Already read
。这是什么意思?我如何正确处理?
答
你非常接近。你只需要删除startWith(null)
作为请求,并抓住第二个响应(你错过了那个getJSON)。
function main({ DOM, HTTP }) {
const usersAPIPath = `https://api.github.com/users`;
const refresh$ = DOM.select(`.refresh`).events(`click`);
const userResponse$ = getJSON({ key: `user` }, HTTP);
const listResponse$ = getJSON({ key: `users` }, HTTP);
const userRequest$ = listResponse$
.map(users => ({
url: R.prop(`url`, R.head(users)),
key: `user`,
}));
const listRequest$ = refresh$
.startWith(`initial`)
.map(_ => ({
url: `${usersAPIPath}?since=${Math.round(Math.random()*500)}`,
key: `users`,
}));
const dom$ = userResponse$.map(res => h('div', JSON.stringify(res)));
return {
DOM: dom$,
HTTP: listRequest$.merge(userRequest$),
};
}
答
因为好奇之心想知道......这里有一个完整的工作示例:
import Cycle from '@cycle/rx-run';
import {div, button, makeDOMDriver} from '@cycle/dom';
import {makeFetchDriver} from '@cycle/fetch';
import R from 'ramda'
function main({DOM, HTTP}) {
const usersAPIPath = 'https://api.github.com/users';
const refresh$ = DOM.select('button').events('click');
const userResponse$ = getJSON({ key: 'user' }, HTTP);
const listResponse$ = getJSON({ key: 'users' }, HTTP);
const userRequest$ = listResponse$
.map(users => ({
url: R.prop('url', R.head(users)),
key: 'user',
}));
const listRequest$ = refresh$
.startWith('initial')
.map(_ => ({
url: `${usersAPIPath}?since=${Math.round(Math.random()*500)}`,
key: 'users',
}));
const dom$ = userResponse$.map(res => div([
button('Refresh'),
div(JSON.stringify(res))
]));
return {
DOM: dom$,
HTTP: listRequest$.merge(userRequest$)
};
function getJSON(by, requests$) {
return requests$.byKey(by.key)
.mergeAll()
.flatMap(res => res.json());
}
}
Cycle.run(main, {
DOM: makeDOMDriver('#main-container'),
HTTP: makeFetchDriver()
});
我花了一段时间才能找出HTTP
是@cycle/fetch
驱动程序,而不是@cycle/http
驱动程序。接下来,一些搜索将ramda
npm库提供了prop
和head
方法。
谢谢,它的作品!但它对我来说似乎仍然有点神奇。我是否正确理解'userRequest $'只是等待'listResponse $'发射任何东西,然后做链中的下一步? – kibin
正确。它将一个来自'listResponse $'的事件映射到一个新的请求。 –
了解。再次感谢,我非常喜欢cycle.js,并会继续深入研究它。 – kibin