2016-10-18 31 views
0

Runnable的例子: https://esnextb.in/?gist=978799bf48a7f914cbbd39df0213d672Cycle.js:制作多选组件。选择组件状态的组合流不输出改变了状态

我试图创建一个多选组件的cycle.js,看看我是否要替换与应用程序的当前UI一个循环应用。

我有一个组件用于多选中的选项。每一个选项被传递形式道具{选择:BOOL,标签:字符串值:诠释}

下面的代码的概述:

期权组件监听本身和切换点击通过将通过折叠逻辑“非”函数生成的布尔流组合起来传递给props $ source中的选项的初始布尔值,将'selected'布尔值组合起来。

然后,选项组件输出它的状态流,以便Multiselect组件可以引用它以便返回选定值的流等。

Multiselect组件接收一个道具$ source,其中包含一个包含选项[{selected,label,value} ...]的流。

从这些选项中,它构造了一个Option组件数组流。

然后将选项组件的流展平为虚拟dom树的数组流(每个选项一个)。

Option组件的流也被拼合成状态数组流(每个选项一个)。

这里的问题开始的地方:

两者的如果我叫.observe(执行console.log)对他们的上面只记录一次。

为了显示多选,我然后映射选项的虚拟dom树的数组流,以生成多选的虚拟dom树。

我也将这个vtree流与状态流结合起来,这样我就可以同时使用console.log(因为观察只记录一次)。

当我登录他们时,vtree数组确实会改变,但所有选项的状态总是与它们的初始状态相同。

这只会发生如果选项是孤立的。如果它们不是孤立的,它们都会响应点击它们中的任何一个,但它们的状态会被记录为已更改。

这是怎么回事?为什么孤立的问题?因为所有合并的流不会每次都发射?我在做什么完全非惯用?

http://pastebin.com/RNWvL4nf这里还有一个pastebin。我想把它放在webpackbin上,但它不会下载我需要的软件包。

import * as most from 'most'; 
import {run} from '@cycle/most-run'; 
import {div, input, p, makeDOMDriver, li, ul, span, h2} from '@cycle/dom'; 
import fp from 'lodash/fp' 
import isolate from '@cycle/isolate' 

// props : { selected : Bool, label : String, value: Int} 
function Option({DOM, props$}) { 
    const click$ = DOM.select('.option').events('click') 
    // a stream of toggle functions. one for each click 
    const toggle$ = click$ 
         .map(() => bool => !bool) 
    /// stream of toggle functions folded upon the inital value so that clicking the option checks if off and on 
    const selected$ = props$.map(prop => toggle$.scan((b, f) => f(b), prop.selected)).join() 
    // a stream of states which has the same structure as props, but toggled 'selected' field according to selected$ stream 
    const state$ = most.combineArray((props, selected) => ({...props, selected}), [props$, selected$]) 
    // the state mapped to a representation of the option 
    const vtree$ = state$.map(state => { 
     return li('.option', {class: {selected: state.selected}}, [ 
      input({attrs: {type: 'checkbox', checked: state.selected}}), 
      p(state.label), 
     ]) 
    }) 
    // returns the stream of state$ so that multiselect can output a stream of selected values 
    return { 
     DOM: vtree$, 
     state$, 
    } 
} 

function Multiselect({DOM, props$}) { 
    // a stream of arrays of isolated Option components 
    const options$ = props$.map(
     options => 
      options.map(it => 
       isolate(Option)({DOM, props$: most.of(it)}))) 
       // Option({DOM, props$: most.of(it)}))) // comment above line and uncomment this one. Without isolation the component doesn't work correctly, but the states are updated 

    // a stream of arrays of virtual tree representations of child Option components 
    const optionsVtree$ = options$.map(options => fp.map(fp.get('DOM'), options)) 
            .map(arrayOfVtree$ => most.combineArray(Array, arrayOfVtree$)) 
            .join() 
    // a stream of arrays of states of child Option components 
    const optionStates$ = options$.map(options => fp.map(fp.get('state$'), options)) 
            .map(arrayOfState$ => most.combineArray(Array, arrayOfState$)) 
            .join() 
           // .map(fp.filter(fp.get('selected'))) 

    // here the virtual trees of options are combined with the state stream so that I can log the state. I only use the virtual dom trees 
    const vtree$ = optionsVtree$.combine(Array, optionStates$).map(([vtrees, states]) => { 
     console.log(states.map(state => state.selected)); // this always prints the initial states 
     // console.log(vtrees); // but the vtrees do change 
     return div('.multiselect', [ 
      ul('.options', vtrees) 
     ]) 
    }) 

    const sinks = { 
     DOM: vtree$, 
     optionStates$ 
    }; 
    return sinks; 
} 

run(Multiselect, { 
    DOM: makeDOMDriver('#app'), 
    props$:() => most.of([ 
     {value: 0, label: 'Option 1', selected: false}, 
     {value: 1, label: 'Option 2', selected: false}, 
     {value: 2, label: 'Option 3', selected: false}, 
     {value: 3, label: 'Option 4', selected: false}, 
    ]) 
}); 

编辑: franciscotln好心地显露在我的一些工作的例子。 https://gist.github.com/franciscotln/e1d9b270ca1051fece868738d854d4e9 如果道具是一个简单的数组,但不包含在observable中,它就可以工作。也许是因为如果它是数组的可观察值,它需要一个可观察的组件数组而不是一组简单的子组件。

然而,这两者并不等价。使用我的原始版本(其中的选项是数组流),props $可以是除.of可观察值之外的其他东西。它的价值可以在程序的过程中改变,而第二个我坚持原始数组。

是否存在一些孤立组件数组流的问题?

const props = [{value: 0, label: 'Option 1', selected: false}, 
       {value: 1, label: 'Option 2', selected: false}, 
       {value: 2, label: 'Option 3', selected: false}, 
       {value: 3, label: 'Option 4', selected: false}] 
// a stream of arrays of isolated Option components 
const options = props.map(prop => 
    isolate(Option)({ 
     DOM, 
     props$: most.of(prop) 
    }) 
); 

回答

0

@tusharmath在循环gitter聊天中发现我做错了什么。

显然,所有我需要做的就是调用.multicast()上选择组件阵列的流:

​​

事做冷热观测。我想,被冷酷的可观察物灼伤。

这是他的解释。

我很想尽我所能解释这里的专家 。隔离将范围参数附加到创建的虚拟DOM节点 。现在你的情况,你在这里创建虚拟DOM两次

因为两个订阅 - DOM: https://esnextb.in/?gist=978799bf48a7f914cbbd39df0213d672状态$: https://esnextb.in/?gist=978799bf48a7f914cbbd39df0213d672两个 虚拟域有不同的范围有效的事件侦听器使用 不同的范围和DOM元素有不同的范围。