如何使用 Cycle.js 创建动态、重复的元素列表

How do I create a dynamic, repeating list of elements with Cycle.js?

本文关键字:元素 列表 动态 何使用 Cycle js 创建      更新时间:2023-09-26

使用 Cycle.js,我正在尝试创建一个视图,该视图在给定一组数据点时呈现动态数量的组件。但是,我不知道如何创建重复视图。

我已经将所有内容剥离回我认为它应该如何工作的最基本的示例。希望有人能指出我错过了什么。

/*
    Expected:
    Given an array of data objects, create the following DOM
    <div class="container">
        <h1 class=".data">Element 1</h1>
        <h1 class=".data">Element 2</h1>
        <h1 class=".data">Element 3</h1>
        <h1 class=".data">Element 4</h1>
        ...
    </div>
    Result:
    <div class="container">
        <h1 class=".data">Element 9</h1>
    </div>
*/
function view( data$ ){
    return Rx.Observable.of(
        div('.container', data$.map( data =>
            h1('.data', `Element: ${ data.id }`)
        ))
    );
}
function main( sources ) {
    // Create an array of objects
    const arr = [];
    for( let i = 0; i < 10; i++ ){
        arr.push({
            id: `id ${i}`
        })
    }
    // Convert array to an observable
    const data$ = Rx.Observable.from(arr);
    const vtree$ = view( data$ );
    return {
        DOM: vtree$
    };
}
const drivers = {
    DOM: CycleDOM.makeDOMDriver('#mountPoint')
};
Cycle.run( main, drivers );

数组有 10 个项目,因此可观察量将发出 10 个项目。可观察量表示一段时间内的数据。因此,您的可观察量代表 10 个时间点。其中只有最新的将被使用。这就是为什么你只看到"元素9"。

与其将数组转换为可观察量,不如创建一个仅包含一个项目的可观察量:u 数组。

Rx.Observable.from(arr)更改为Rx.Observable.just(arr)

下一个问题是您的视图函数:

function view( data$ ){
    return Rx.Observable.of(
        div('.container', data$.map( data =>
            h1('.data', `Element: ${ data.id }`)
        ))
    );
}

视图函数采用data$参数。data$读为data streamstream of data。所以你的函数接收一个流到目前为止,这是正确的。

但是现在您正在创建一个新的可观察对象 通过 Observable.of .这不是你想做的。相反,您可能只想将data$(即数据流)转换为虚拟 DOM 节点流:

function view( data$ ){
    return data$.map( data =>
        // here you should return a virtual DOM node
    )
}

请记住:一段时间内的数据data$。对于每个时间点,您都有一些数据。对于每个时间点,你都希望有一些 DOM 树。

function view( data$ ){
    return data$.map( data =>
        div('.container', 
          // data is not a single of your items but the whole array of items
          // hence we can map over it and transform each item into a child nod:
          data.map((item) => div('.item', item.id))
        )
    )
}

注意:data$.map与data.map非常不同。第一个转换/映射一个可观察数组,后者转换/映射一个经典数组。

奖金:

for( let i = 0; i < 10; i++ ){
     arr.push({
        id: `id ${i}`
     })
 }

您正在以程序化方式创建数组。您可能更喜欢创建大小为 10 的数组并将其转换为包含项目的数组的功能方式:

Array.apply(Array, {length: 10}).map(
    (_,index) => ({id: `id: ${index}`})
)

Cycle 有一个 Collection 模块。它采用对象数组流并隔离它们。我用 npm 获取这些模块并使用 webpack 部署。

import Cycle from '@cycle/xstream-run';
import Collection from '@cycle/collection';
import {div,h1} from '@cycle/dom';
import { makeDOMDriver } from '@cycle/dom';
import xs from 'xstream';
function view( comb$ ){
  return comb$.debug('view').map( tup =>{
    const item = tup[0];
    const clicked = tup[1];
    return div('.container', [ h1( '.data', `Element: ${item.id} clicked: ${clicked}`)]);
  });
}
/* Item Component */
function Item ( sources ){
  const intent$ = sources.DOM   //Events on DOM are limited to only ones on sink DOM
    .select('div')
    .events('click').mapTo('yes').startWith('no').debug('item clicks');
      
  return {
    DOM: view( xs.combine( sources.itemJaJa, intent$) )
  };
}
function main(sources) {
  const arr = [];
  for( let i = 0; i < 10; i++ ){
    arr.push(
      //The way Collection add the obj to the source is odd
      //this is what's worked for me
      { id_to_collection: i, //identifier used by collection
        itemJaJa:{ 
          id: `id ${i}`
        }
      } );
  }
  
  const items = Collection.gather(Item, sources, xs.of( arr),'id_to_collection'  );  
  const vtrees$ = Collection.pluck( items, item=>item.DOM);  
  return {
    DOM:  vtrees$.map( itemDomList => div('.top',itemDomList)),
  };    
}
const drivers ={
  DOM: makeDOMDriver('#app')
};
Cycle.run(main, drivers);