js:创建一个多选择组件.选项组件状态的组合流不输出改变的状态
Cycle.js: making a multiselect component. Combined stream of option component states doesn't output changed states
可运行示例:https://esnextb.in/?gist=978799bf48a7f914cbbd39df0213d672
我试图为cycle.js创建一个多选组件,看看我是否想用一个循环应用程序取代应用程序的当前UI。
我有一个组件用于multiselect中的选项。每个选项以{selected: Bool, label: String, value: Int}
的形式被传递给props。下面是代码的概述:
Option组件监听自身的点击,并通过在props$ source中传递给该选项的初始布尔值上折叠逻辑'not'函数所生成的布尔值流,来切换'selected'布尔值。
Option组件然后输出一个它的状态流,这样Multiselect组件就可以引用它来返回一个被选中的值流等等。
Multiselect组件接收一个props$ source,其中包含一个带有选项[{selected, label, value}…]的流。
从这些选项中构造一个Option组件数组流。
选项组件流然后被扁平化为虚拟dom树数组流(每个选项一个)。
Option组件流也被扁平化为状态数组流(每个选项一个)。
问题就出在这里了:
如果我在上面调用.observe(console.log),上面两个都只记录一次。
为了显示多选,我然后映射选项的虚拟dom树数组流,以生成多选的虚拟dom树。
我还将这个vtree流与状态流结合起来,这样我就可以同时使用console.log(因为observe只记录它们一次)。
当我记录它们时, 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},
])
});
编辑:弗朗西斯科好心地举了一个可行的例子,它揭示了我的一些想法。https://gist.github.com/franciscotln/e1d9b270ca1051fece868738d854d4e9如果props是一个简单的数组,没有被包装在一个可观察对象中,它就可以工作。也许是因为如果它是一个数组的可观察对象它需要一个组件数组的可观察对象而不是一个简单的子组件数组。
然而,两者并不相等。在我最初的版本中(其中的选项是一个数组流),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)
})
);
@tusharmath在循环中gitter chat发现我做错了什么
显然,我所要做的就是在选项组件数组流上调用.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两个vdom具有事件侦听器正在使用的不同作用域不同的作用域和dom元素有不同的作用域
- 从组件状态的数组中删除元素
- Reactjs:在修改对象之前,是否需要复制处于组件状态的对象
- 在Redux中使用组件状态是反模式的吗
- 如何处理需要子组件状态的Meteor数据
- 单击按钮更改组件状态
- 当登录状态为组件状态时,如何使用react路由器实现依赖登录的路径
- 我是否必须在 React 中使用 this.state 来维护组件状态
- 如何使用react路由器将顶级组件状态传递给Routes
- React组件状态与道具动态输入
- 在子组件之间共享父组件状态'州
- 当父组件状态改变时,如何强制子组件重新呈现
- 有条件地绑定组件状态
- js:创建一个多选择组件.选项组件状态的组合流不输出改变的状态
- 从props中初始化组件状态
- 为什么不将redux存储状态存储在本地组件状态中呢?
- 将Facebook Web SDK与ReactJS组件状态集成
- 当从父组件状态传递时,React prop没有在正确的时间更新
- 如何将包含组件'状态的值传递回父组件
- 检查事件函数中的组件状态是否有效
- 当值被分配给组件状态时,为什么console.log打印之前的状态