0

実行可能な例: https://esnextb.in/?gist=978799bf48a7f914cbbd39df0213d672

アプリケーションの現在の UI をサイクル アプリに置き換えるかどうかを確認するために、cycle.js の複数選択コンポーネントを作成しようとしています。

複数選択内のオプション用に 1 つのコンポーネントがあります。各オプションは、フォーム {selected: Bool, label: String, value: Int} で渡された props を取得します。

コードの概要は次のとおりです。

Option コンポーネントはそれ自体のクリックをリッスンし、props$ ソースのオプションに渡された最初のブール値に論理「not」関数を折りたたむことによって生成されたブール値のストリームを組み合わせることで、「選択された」ブール値を切り替えます。

次に、Option コンポーネントはその状態のストリームを出力し、Multiselect コンポーネントがそれを参照して、選択された値などのストリームを返すことができるようにします。

Multiselect コンポーネントは、オプション [{selected, label, value}...] を持つストリームを含む props$ ソースを受け取ります。

これらのオプションから、Option コンポーネントの配列のストリームを構築します。

Option コンポーネントのストリームは、仮想 DOM ツリーの配列のストリーム (オプションごとに 1 つ) にフラット化されます。

オプション コンポーネントのストリームも、状態の配列のストリーム (オプションごとに 1 つ) にフラット化されます。

ここから問題が始まります。

上記の両方で .observe(console.log) を呼び出すと、一度だけログに記録されます。

複数選択を表示するために、オプションの仮想 DOM ツリーの配列のストリームをマップして、複数選択の仮想 DOM ツリーを生成します。

また、この vtree ストリームを状態ストリームと組み合わせて、両方を console.log できるようにします (observe はそれらを 1 回しかログに記録しないため)。

それらをログに記録すると、vtree 配列は変更されますが、すべてのオプションの状態は常に初期状態と同じです。

これは、オプションが分離されている場合にのみ発生します。それらが分離されていない場合、それらはいずれかをクリックするとすべて応答しますが、それらの状態は変更されたものとしてログに記録されます。

ここで何が起こっているのですか?なぜ物質を分離するのですか?結合されたすべてのストリームが毎回起動するわけではないためですか? 私がやっていることは完全に慣用的ではありませんか?

http://pastebin.com/RNWvL4nfここにもペーストビンがあります。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 小道具がオブザーバブル内にラップされていない単純な配列である場合、それは機能します。おそらく、それが配列のオブザーバブルである場合、子コンポーネントの単純な配列ではなく、コンポーネントの配列のオブザーバブルが必要になるためです。

ただし、この 2 つは等価ではありません。私の元のバージョン (オプションは配列のストリーム) では、props$ は単なる .of オブザーバブル以外のものにすることができます。その値はプログラムの過程で変化する可能性がありますが、2番目の値では元の配列に固執しています。

分離されたコンポーネントの配列のストリームに問題はありますか?

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

1 に答える 1

0

@tusharmath サイクルの Gitter チャットで、私が間違っていたことを発見しました。

どうやら私がしなければならなかったことは、オプション コンポーネントの配列のストリームで .multicast() を呼び出すことだけでした。

const options$ = props$.map(
        options => 
            options.map(it => 
                isolate(Option)({DOM, props$: most.of(it)}))).multicast()

ホットおよびコールドの観測量と関係があります。私が推測する冷たい観測物によって火傷を負った。

これが彼の説明です。

ここで専門家から理解した限り、私は説明しようとはしません。分離は、作成された仮想 DOM ノードにスコープ パラメータをアタッチします。あなたの場合、仮想DOMを2回作成しています

ここに 2 つのサブスクリプションがあるため — DOM : https://esnextb.in/?gist=978799bf48a7f914cbbd39df0213d672 state$: https://esnextb.in/?gist=978799bf48a7f914cbbd39df0213d672 scope と dom 要素のスコープは異なります。

于 2016-10-19T13:52:02.213 に答える