Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to request data sequentially in Cycle.js?

I’m new to reactive programming and toying around with cycle.js, trying to implement who to follow box from this tutorial. But I understood that for proper implementation (and learning purposes) I don’t have one piece of data: full user name. I can get it by sequentially getting users and then full user data from server. In imperative style I would do something like this:

fetch(`https://api.github.com/users`)
  .then(data => data.json())
  .then(users => fetch(users[0].url))
  .then(data => data.json())
  .then(/* ... work with data ... */)

But how do I do it in cycle? I’m using fetch driver and trying something like this:

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

where getJSON is

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

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

And I’m always getting some cryptic (for me) error like: TypeError: Already read. What does it mean and how do I handle it properly?

like image 899
alice kibin Avatar asked Nov 19 '15 22:11

alice kibin


1 Answers

You were quite close. You just need to remove startWith(null) as a request, and grabbing the second response (you were missing the getJSON for that one).

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$),
  };
}
like image 66
André Staltz Avatar answered Oct 24 '22 02:10

André Staltz