使用Cycle.js将index响应存储到indexedDB

时间:2018-04-16 01:14:03

标签: cyclejs xstream-js

我正在学习Cycle.JS并遇到挑战。我有一个组件将从HTTP调用中获得结果,并且我希望在indexDB中保留此响应。但是,我觉得持久性请求是另一个组件的责任。

我的问题是:

  1. 这是一个自定义驱动程序的用例,它将HTTP响应持久保存到indexDB吗?
  2. 另一个组件如何访问未发出的请求的响应流?
  3. 当我尝试从HTTP源中选择类别时,没有任何内容记录到控制台。我使用xstream,所以流应该很热,我希望调试输出。这是怎么回事?
  4. 以下是进行HTTP调用的组件:

    import { Feed } from './feed'
    
    export function RssList ({HTTP, props}, feedAdapter = x => x) {
      const request$ = props.url$
        .map(url => ({
          url: url,
          method: 'GET',
          category: 'rss'
        }))
    
      const response$ = HTTP
        .select('rss')
        .flatten()
        .map(feedAdapter)
    
      const vDom$ = response$
        .map(Feed)
        .startWith('')
    
      return {
        DOM: vDom$,
        HTTP: request$
      }
    }
    

    以下是我在应用级别访问响应的尝试:

    export function main (sources) {
      const urlSource = url$(sources)
      const rssSink = rss$(sources, urlSource.value)
    
      const vDom$ = xs.combine(urlSource.DOM, rssSink.DOM)
        .map(([urlInput, rssList]) =>
          <div>
            {urlInput}
            {rssList}
          </div>
        )
    
      sources.HTTP.select('rss').flatten().debug() // nothing happens here
    
      return {
        DOM: vDom$,
        HTTP: rssSink.HTTP
      }
    }
    

2 个答案:

答案 0 :(得分:2)

选择主(父)组件中的类别是正确的方法,并且受支持。

sources.HTTP.select('rss').flatten().debug()没有记录任何内容的唯一原因是因为debug的工作原理并非如此。它不会“订阅”流并创建副作用。 debug基本上类似于map运算符,它使用标识函数(始终将x作为输入并输出x),但将日志记录操作作为副作用。因此,您需要将.debug()替换为.addListener({next: x => console.log(x)}),或者使用.debug()输出的流,并将其与用于接收器的运算符管道挂钩。换句话说,debug中间日志记录副作用,而不是目标日志记录副作用。

答案 1 :(得分:1)

问题#1:自定义HTTP-&gt; IDB驱动程序:这取决于项目的性质,对于一个简单的例子,我使用了一般CycleJS IDB Driver。请参阅下面的示例或codesandbox.io example.

问题2:组件共享流:由于组件和main共享相同的源/接收器API,您可以将一个组件的输出(sink)链接到输入(source )另一个。请参阅下面的示例或codesandbox.io example.

问题#3:debug和记录:由于权威的literallyAndré Staltz指出debug需要插入已完成的流中循环,IE,已经订阅/收听的流。

在您的示例中,您可以将debug放入RssList组件中:

const response$ = HTTP
  .select('rss')
  .flatten()
  .map(feedAdapter)
  .debug()

或者为main示例添加一个监听器:

sources.HTTP.select('rss').flatten().debug()
  .addListener({next: x => console.log(x)})

或者,我喜欢做的是,包括一个日志驱动程序:

run(main, {
    DOM: makeDOMDriver('#app'),
    HTTP: makeHTTPDriver(),
    log: log$ => log$.addListener({next: log => console.log(log)}),
})

然后,我只是复制一个流并将其发送到log接收器:

const url$ = props.url
const http$ = url$.map(url => ({url: url, method: 'GET', category: 'rss'}))
const log$ = url$

return {
  DOM: vdom$,
  HTTP: http$,
  log: log$,
}

这里有一些示例代码,用于使用两个共享数据的组件和一般的IndexedDB驱动程序向IndexedDB存储发送HTTP响应:

function main(sources) {
  const header$ = xs.of(div('RSS Feed:'))

  const rssSink = RssList(sources) // input HTTP select and props
                                   // output VDOM and data for IDB storage
  const vDom$ = xs.combine(header$, rssSink.DOM) // build VDOM
    .map(([header, rssList]) => div([header, rssList])
  )
  const idbSink = IdbSink(sources, rssSink.IDB) // output store and put HTTP response

  return {
    DOM: vDom$,
    HTTP: rssSink.HTTP, // send HTTP request
    IDB: idbSink.put, // send response to IDB store
    log: idbSink.get, // get and log data stored in IDB
  }
}

function RssList({ HTTP, props }, feedAdapter = x => x) {
  const request$ = props.url$
    .map(url => ({url: url, method: 'GET', category: 'rss'}))

  const response$ = HTTP.select('rss').flatten().map(feedAdapter)
  const idb$ = response$
  const vDom$ = response$
    .map(Feed)
    .startWith(div('','...loading'))

  return {
    DOM: vDom$,
    HTTP: request$,
    IDB: { response: idb$ },
  }
}
function Feed (feed) {
  return div('> ' + feed)
}

function IdbSink(sources, idb) {
  return {
    get: sources.IDB.store('rss').getAll()
      .map(obj => (obj['0'] && obj['0'].feed) || 'unknown'),
    put: idb.response
      .map(feedinfo => $put('rss', { feed: feedinfo }))
  }
}

run(main, {
  props: () => ({ url$: xs.of('http://lorem-rss.herokuapp.com/feed') }),
  DOM: makeDOMDriver('#root'),
  HTTP: makeHTTPDriver(),
  IDB: makeIdbDriver('rss-db', 1, upgradeDb => {
    upgradeDb.createObjectStore('rss', { keyPath: 'feed' })
  }),
  log: log$ => log$.addListener({next: log => console.log(log)}),
})

这是一个人为的例子,只是为了探讨所提出的问题。 Codesandbox.io example.