如何在Cycle.js中顺序请求数据?

如何在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$), 
    }; 
} 
+0

谢谢,它的作品!但它对我来说似乎仍然有点神奇。我是否正确理解'userRequest $'只是等待'listResponse $'发射任何东西,然后做链中的下一步? – kibin

+1

正确。它将一个来自'listResponse $'的事件映射到一个新的请求。 –

+0

了解。再次感谢,我非常喜欢cycle.js,并会继续深入研究它。 – kibin

因为好奇之心想知道......这里有一个完整的工作示例:

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库提供了prophead方法。