Runnable示例: https://esnextb.in/?gist=978799bf48a7f914cbbd39df0213d672
我正在尝试为cycle.js创建一个多选组件,以查看是否要用循环应用程序替换应用程序的当前UI。
我在multiselect中有一个组件用于选项。每个选项都以{selected:Bool,label:String,value:Int}
的形式传递道具以下是代码概述:
Option组件侦听自身的点击并通过组合通过折叠逻辑'not'函数生成的布尔流来切换'selected'布尔值,这些布尔值传递给props $ source中的选项的初始布尔值。
然后,Option组件输出其状态流,以便Multiselect组件可以引用它以便返回选定值的流等。
Multiselect组件接收props $ source,其中包含带有[{selected,label,value} ...]选项的流。
从这些选项中,它构建了一个Option组件数组流。
然后将Option组件流平展为虚拟dom树阵列流(每个选项一个)。
Option组件流也被扁平化为状态数组流(每个选项一个)。
以下是问题的开始点:
如果我在它们上面调用.observe(console.log),则上述两者都只记录一次。
为了显示多选项,我将映射选项的虚拟dom树阵列流,以生成多选的虚拟dom树。
我还将这个vtree流与状态流结合起来,以便我可以同时使用console.log(因为observe只记录它们一次)。
当我记录它们时, 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 如果道具是一个没有包含在一个可观察的内容中的简单数组,它就可以工作。也许是因为如果它是一个可观察的数组,它需要一个可观察的组件数组,而不是一个简单的子组件数组。
然而,这两者并不相同。使用我的原始版本(其中选项是数组流),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 :(得分:0)
@tusharmath在周期中,gitter聊天发现我做错了什么。
显然,我所要做的就是在选项组件数组流上调用.multicast():
const options$ = props$.map(
options =>
options.map(it =>
isolate(Option)({DOM, props$: most.of(it)}))).multicast()
与冷热可观察物有关。我想,被冷的观察者烧伤了。
这是他的解释。
我试图解释我从专家那里得到的解释 这里。 isolate将范围参数附加到虚拟dom节点 创建。现在你正在创建虚拟dom两次
因为这里有两个订阅 - DOM: https://esnextb.in/?gist=978799bf48a7f914cbbd39df0213d672州$: https://esnextb.in/?gist=978799bf48a7f914cbbd39df0213d672这两个人 VDoms有效地使用事件监听器 不同的范围和dom元素具有不同的范围。