RxJs объединяет последние, кажется, имитируют дополнительное обновление - PullRequest
0 голосов
/ 01 марта 2019

Хотя я знаю, что то, что упомянуто в теме, звучит смешно, но когда вы смотрите на код, это кажется более очевидным.Однако я потратил несколько часов, пытаясь пройти через API и поиграть с моим кодом без логического объяснения, почему он не работает в соответствии с ожиданиями.

В моем коде есть кнопки x и y, которые приclicked будет увеличивать их собственный текстовый контент с определенной суммой, которая равна 3 для x и 1 для y.Начальные значения x и y инициализируются равными 2 и 5 соответственно.Я использовал combLatest с целью получить текстовое содержимое кнопки «Сумма» для обновления новыми значениями x и y.

Хотя в большинстве случаев это работает нормально, при первом нажатии кнопки x или yтекстовое содержание показывает правильное число, но сумма, кажется, получила следующее значение (будущее значение?), которое я ожидаю получить при последующем щелчке.Мне трудно объяснить это словами, но я уверен, что если вы попробуете нажать любую из кнопок дважды, вы обнаружите проблему.Спасибо за чтение этого, пожалуйста, помогите мне.

const makeButtonTextUpdater = buttonElt => value => buttonElt.textContent = value;

const xElt = document.getElementById('x');
const yElt = document.getElementById('y');
const sumElt = document.getElementById('sum');
const xClick$ = rxjs.fromEvent(xElt, 'click');
const yClick$ = rxjs.fromEvent(yElt, 'click');
const sumClick$ = rxjs.fromEvent(sumElt, 'click');

const xValue$ = new rxjs.Observable(s => {
  s.next(2); // default value
  xClick$.subscribe(e => {
    s.next(parseInt(e.target.textContent) + 3)
  });
});
const yValue$ = new rxjs.Observable(s => {
  s.next(5); // default value
  yClick$.subscribe(e => {
    s.next(parseInt(e.target.textContent) + 1)
  });
});
const sumValue$ = new rxjs.Observable(s => {
  rxjs.combineLatest(xValue$, yValue$).subscribe(([x, y]) => {
    s.next(parseInt(x) + parseInt(y));
  });
});

xValue$.subscribe(makeButtonTextUpdater(xElt));
yValue$.subscribe(makeButtonTextUpdater(yElt));
sumValue$.subscribe(makeButtonTextUpdater(sumElt));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.js"></script>
<label>x: <button id="x">0</button></label>
<label>y: <button id="y">0</button></label>
<label>sum: <button id="sum">0</button></label>

PS: я знаю, что есть лучшие способы выполнить работу с трубами, но, поскольку я новичок, я хотел бы исследовать вещи в своем собственном темпе.Хотя я открыт для альтернативных решений, мне очень хотелось бы знать, почему мой код не работает.

Ответы [ 3 ]

0 голосов
/ 01 марта 2019

Вы также можете попробовать следующий подход:

const makeButtonTextUpdater = buttonElt => value => buttonElt.textContent = value;

const xElt = document.getElementById('x');
const yElt = document.getElementById('y');
const sumElt = document.getElementById('sum');
const xClick$ = rxjs.fromEvent(xElt, 'click');
const yClick$ = rxjs.fromEvent(yElt, 'click');
const sumClick$ = rxjs.fromEvent(sumElt, 'click');

const xValue$ = xClick$.pipe(
                  rxjs.operators.pluck('target', 'textContent'),
                  rxjs.operators.map(v => parseInt(v) + 3),
                  rxjs.operators.startWith(2),
                  rxjs.operators.tap(makeButtonTextUpdater(xElt))
                  );

   const yValue$ = yClick$.pipe(
                  rxjs.operators.pluck('target', 'textContent'),
                  rxjs.operators.map(v => parseInt(v) + 1),
                  rxjs.operators.startWith(5),
                  rxjs.operators.tap(makeButtonTextUpdater(yElt))
               );

   const sumValue$ = rxjs.combineLatest(xValue$, yValue$)
                     .pipe(
                          rxjs.operators.tap(console.log),
                          rxjs.operators.map(v => v[0]+v[1])
                      );

  
//xValue$.subscribe(makeButtonTextUpdater(xElt));
//yValue$.subscribe(makeButtonTextUpdater(yElt));
sumValue$.subscribe(makeButtonTextUpdater(sumElt));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.js"></script>
<label>x: <button id="x">0</button></label>
<label>y: <button id="y">0</button></label>
<label>sum: <button id="sum">0</button></label>
0 голосов
/ 01 марта 2019

Причиной проблемы является то, что xClick $ получает подписку дважды:

  1. xValue $ .subscribe (makeButtonTextUpdater (xElt));
  2. rxjs.combineПоследняя внутренняя подписка;

При нажатии кнопки x (x = 2) подписка xClick $ выполняется как:

  1. xValue $ .subscribe (makeButtonTextUpdater (xElt));// испускает (2 + 3) и обновляет DOM
  2. rxjs.combineLatest внутренняя подписка принимает самое последнее значение из DOM (5 + 3) = 8, а подписка CombinLatest принимает x = 8, y = 5

const makeButtonTextUpdater = buttonElt => value => buttonElt.textContent = value;

const xElt = document.getElementById('x');
const yElt = document.getElementById('y');
const sumElt = document.getElementById('sum');
const xClick$ = rxjs.fromEvent(xElt, 'click');
const yClick$ = rxjs.fromEvent(yElt, 'click');
const sumClick$ = rxjs.fromEvent(sumElt, 'click');

const xValue$ = new rxjs.Observable(s => {
  s.next(2); // default value
  xClick$.subscribe(e => {
    console.log('xClick=', e.target.textContent )
    s.next(parseInt(e.target.textContent)+3)
  });
});
const yValue$ = new rxjs.Observable(s => {
  s.next(5); // default value
  yClick$.subscribe(e => {
            console.log('xClick=', e.target.textContent )

    s.next(parseInt(e.target.textContent) + 1)
  });
});


const sumValue$ = new rxjs.Observable(s => {
  rxjs.combineLatest(xValue$, yValue$).subscribe(([x, y]) => {
    console.log(x, y)
    s.next(parseInt(x) + parseInt(y));
  });
});

xValue$.subscribe(makeButtonTextUpdater(xElt));
yValue$.subscribe(makeButtonTextUpdater(yElt));

sumValue$.subscribe(makeButtonTextUpdater(sumElt));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.js"></script>
<label>x: <button id="x">0</button></label>
<label>y: <button id="y">0</button></label>
<label>sum: <button id="sum">0</button></label>
0 голосов
/ 01 марта 2019

Почему ваш код не работал:

Э, это сложно ... У вас определенно есть двойная подписка на кнопки, то есть код внутри new Observable для кнопок будетзапустить дважды (сначала, когда подписка на nValue$, а затем, когда combineLatest).Запуск дважды означает, что у него есть два обработчика для каждого btn onClick.

Итак, когда вы нажимаете x или y - вы .next получаете две цепочки Observable: одну, которая обновляет текст btn, а другую - суммуОбновление значения.

Сначала выполняется цепочка для обновления текста кнопки и обновляется значение btn.

Затем активируется цепочка для обновления текста суммы.И когда он суммирует значения - он читает уже обновленные значения из текста btn.Из-за предыдущей цепочки выполните.

Попробуйте внести изменения в свой код подписок по клику, чтобы выполнить регистрацию.Например,

yClick$.subscribe(e => {
        const value = parseInt(e.target.textContent)
        console.log('y click', value);
        s.next(value + 1);
      });

Вы увидите, что он запускается дважды.Сначала он читает значение в t1 и обновляет его.Затем он выполняется во второй раз и теперь читает следующее значение из текста btn.

Это, кажется, имеет место.

Важное примечание: этот подход с наблюдаемыми конструкторами и внутреннимподписки следует в первую очередь использовать для обучения.Это подвержено ошибкам и обычно чрезмерно, поскольку большинство задач решаются с использованием существующих операторов или их объединением.Если вы используете конструктор - скорее всего, вы делаете это неправильно.

Существует множество альтернатив конструктора для создания в Observable:

Итак, вот обновленный пример использования каналов:

const makeButtonTextUpdater = buttonElt => value => buttonElt.textContent = value;
const xElt = document.getElementById('x');
const yElt = document.getElementById('y');
const sumElt = document.getElementById('sum');
const xClick$ = rxjs.fromEvent(xElt, 'click');
const yClick$ = rxjs.fromEvent(yElt, 'click');
const sumClick$ = rxjs.fromEvent(sumElt, 'click');

const xSumm$ = xClick$.pipe(
  rxjs.operators.startWith(2),
  rxjs.operators.scan((acc)=>(acc + 3))
)

const ySumm$ = yClick$.pipe(
  rxjs.operators.startWith(5),
  rxjs.operators.scan((acc)=>(acc + 1))
);

xSumm$.subscribe(makeButtonTextUpdater(xElt));
ySumm$.subscribe(makeButtonTextUpdater(yElt));

rxjs
  .combineLatest(xSumm$, ySumm$, (x, y)=>x+y)
  .subscribe(makeButtonTextUpdater(sumElt));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.js"></script>
<label>x: <button id="x">0</button></label>
<label>y: <button id="y">0</button></label>
<label>sum: <button id="sum">0</button></label>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...