2015-11-19 7 views
8

Sono nuovo alla programmazione reattiva e gironzolo con cycle.js, cercando di implementare chi seguire la casella da this tutorial. Ma ho capito che per una corretta implementazione (e scopi di apprendimento) non ho un pezzo di dati: nome utente completo. Posso ottenerlo sequenziando gli utenti e quindi i dati completi dell'utente dal server. In stile imperativo vorrei fare qualcosa del genere:Come richiedere i dati sequenzialmente in 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 ... */) 

Ma come faccio a farlo in ciclo? sto usando prendere conducente e cercando qualcosa di simile:

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$, 
    }; 
} 

dove getJSON è

function getJSON(by, requests$) { 
    const type = capitalize(firstKey(by)); 

    return requests$ 
    [`by${type}`](firstVal(by)) 
    .mergeAll() 
    .flatMap(res => res.json()); 

e sono sempre ottenere un certo errore criptico (per me) come: TypeError: Already read. Che cosa significa e come lo gestisco correttamente?

risposta

9

Eri piuttosto vicino. Devi solo rimuovere startWith(null) come richiesta e prendere la seconda risposta (ti mancava il getJSON per quello).

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

Grazie, funziona! Ma a me sembra comunque una specie di magia. Capisco correttamente che 'userRequest $ 'aspetta semplicemente' listResponse $ 'per emettere qualcosa e poi fa solo quello che viene dopo nella catena? – kibin

+1

corretto. Mappa un evento da 'listResponse $' a una nuova richiesta. –

+0

Capito. Grazie ancora, mi piace molto cycle.js e continuerò a scavare dentro. – kibin

0

Perché menti indagatrici vogliono sapere ... Ecco un esempio di lavoro completo:

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() 
}); 

ci ho messo un po 'per capire HTTP era il conducente @cycle/fetch, e non il conducente @cycle/http. Successivamente, un po 'di ricerca ha trasformato la libreria npm ramda fornendo i metodi prop e head.