我一直在尝试创建一些cycle.js示例作为嵌套对话框,并使用选择框在它们之间切换.
其中一个对话是官方Github HTTP搜索示例的克隆.
另一个对话是一个更基本的对话,没有HTTP,只有DOM.
我觉得我绕着2号换了我的头,但我对Rx来说相当新,所以可能做得不正确或天真.
在我向搜索页面添加加载指示器之前,这一切似乎都运行良好.
为此,我转过身来:
const vTree$ = responses.HTTP .filter(res$ => res$.request.indexOf(GITHUB_SEARCH_API) === 0) .flatMapLatest(x => x) .map(res => res.body.items) .startWith([]) .map(results => h('div.wrapper', {}, [ h('label.label', {}, 'Search:'), h('input.field', {type: 'text'}), h('hr'), h('section.search-results', {}, results.map(resultView)), ]) )
进入:
const searchResponse$ = responses.HTTP .filter(res$ => res$.request.indexOf(GITHUB_SEARCH_API) === 0) .flatMapLatest(x => x) .map(res => res.body.items) .startWith([]) const loading$ = searchRequest$.map(true).merge(searchResponse$.map(false)) // Convert the stream of HTTP responses to virtual DOM elements. const vtree$ = loading$.withLatestFrom(searchResponse$, (loading, results) => h('div.wrapper', {}, [ h('label.label', {}, 'Search:'), h('input.field', {type: 'text'}), h('span', {}, loading ? 'Loading...' : 'Done'), h('hr'), h('section.search-results', {}, results.map(resultView)), ]) )
我现在有2个问题
每次更改复选框时,会将"复选框值设置为"和"路径已更改"消息记录两次.
HTTP请求日志仅触发一次,但如果您在Dev Tools中观察网络活动,则会同时看到两个GET请求.
谢谢你的帮助!
编辑:解决了我自己的问题.见下面的答案.
我最终通过从头开始重建我的整个应用程序来解决这个问题,直到找到了突破点.
我学到的是你需要添加.share()
到任何可观察的流,这些流将被多个下游的observable订阅/映射/等.
const searchRequest$ = DOM.select('.field').events('input') .debounce(500) .map(ev => ev.target.value.trim()) .filter(query => query.length > 0) .map(q => GITHUB_SEARCH_API + encodeURI(q)) .share() //needed because multiple observables will subscribe // Get search results from HTTP response. const searchResponse$ = HTTP .filter(res$ => res$ && res$.request.url.indexOf(GITHUB_SEARCH_API) === 0) .flatMapLatest(x => x) //Needed because HTTP gives an Observable when you map it .map(res => res.body.items) .startWith([]) .share() //needed because multiple observables will subscribe //loading indication. true if request is newer than response const loading$ = searchRequest$.map(true).merge(searchResponse$.map(false)) .startWith(false) .share() //Combined state observable which triggers view updates const state$ = Rx.Observable.combineLatest(searchResponse$, loading$, (res, loading) => { return {results: res, loading: loading} }) //Generate HTML from the current state const vtree$ = state$ .map(({results, loading}) => .........