1

我正在尝试学习 cyclejs 和反应式编程,但我不知道如何使用值来管理事件。

例如,我需要创建四个函数来进行一些数学运算,例如:

  • 添加
  • 减法
  • 分工
  • 乘法

这是我拥有的代码:

function main ({DOM}) {

  const secondNumber$ = DOM
    .select('.second-number')
    .events('change')
    .map(ev => ev.target.value)
    .startWith(0)

  const firstNumber$ = DOM
    .select('.first-number')
    .events('change')
    .map(ev => ev.target.value)
    .startWith(0)

  const addClick$ = DOM
    .select('.add')
    .events('click')
    .merge(firstNumber$)
    .merge(secondNumber$)
    .filter(value => console.log(value))
    .scan((nb1, nb2) => nb1 + nb2)


  return {
    DOM: addClick$.map(result =>
      div([
        input('.first-number',{type:'text'}),
        input('.second-number',{type:'text'}),
        button('.add', 'Add'),
        h2('Result is : ' + result)
      ])
    )
  };
}

它根本不起作用,我无法在脑海中弄清楚我在那里做错了什么。

我正在寻找一个简单的解释,我怎样才能使它工作?我觉得 secondNumber$ 和 firstNumber$ 的合并流不正确,我找不到原因..

任何想法 ?

编辑:我知道我不应该使用我正在使用的运算符,而是使用 withLatestFrom。

事实是我正在使用 xstream ,所以我必须映射/展平:

import {
    div,
    h1,
    input,
    button
} from '@cycle/dom';

/**
 * Counter
 * @param  {Object} sources Contains the inputs
 * @return {Object} The output sinks
 */
function counter(sources) {

    const input1$ = sources.DOM
        .select('.input1')
        .events('input')
        .map(ev => ev.target.value)
        .startWith(0);

    const input2$ = sources.DOM
        .select('.input2')
        .events('input')
        .map(ev => ev.target.value)
        .startWith(0);

    const add$ = sources.DOM
        .select('.add')
        .events('click');

    const resultAddition$ = add$
        .map(ev => input1$
            .map(value => input2$
                .map(value2 => Number(value) + Number(value2)))
            .flatten())
        .flatten()
        .startWith(0);

    return {
        DOM: resultAddition$.map(item => {
            console.log(item); // triggered each time an input is modified
            return div([
                h1(`Super new value  : ${item}`),
                input('.input1', {
                    attrs: {
                        type: 'text'
                    }
                }),
                input('.input2', {
                    attrs: {
                        type: 'text'
                    }
                }),
                button('.add', 'Ajouter')
            ]);
        })
    };
}

export default counter;

从现在开始,我已经记住了代码应该做什么,映射每次单击操作并将两个 input$ 展平以仅在单击按钮时得到我的结果

事实是结果值在输入时发生变化,而不是在单击时发生变化。更重要的是,只有在第一次单击不是我想要的添加按钮后,它才会更改输入。

这次我做错了什么?

感谢您的回复

4

1 回答 1

5

好像你想要combineLatest的,不是merge的。combineLatest和都是merge“组合运算符”。它们将多个 Observable 组合在一起并输出一个 Observable。但是,combineLatest用于“AND”组合,而merge用于“OR”组合。

您可能需要“AND”,因为您想要第一个数字的值和第二个数字的值。也就是说,您仅在发生添加点击时才需要这些值。在这种情况下,有一个combineLatest被调用的变体withLatestFrom。它允许您从第一个数字和第二个数字中采样值,但仅在添加单击发生时。

const addClick$ = DOM
  .select('.add')
  .events('click')

const added$ = addClick$
  .withLatestFrom(firstNumber$, secondNumber$,
    (click, first, second) => first + second
  )

作为旁注,你不应该做类似的事情.filter(value => console.log(value))。过滤器的功能是一个谓词。它应该是一个返回布尔值的“条件”函数。如果要调试,请使用.do(value => console.log(value)).

PS:我假设您使用的是 RxJS v4。

于 2016-09-26T17:12:55.780 回答