RxJS Observable Share состояние startWith () в слиянии () - PullRequest
0 голосов
/ 20 января 2019

Как я могу разделить состояние startWith(false) между 3 потоками? Я попытался использовать withLatestFrom(), но получил несколько странных ошибок для значения.

const Home = componentFromStream(prop$ => {
  const { handler: toggleHandler, stream: toggle$ } = createEventHandler();
  const { handler: showHandler, stream: show$ } = createEventHandler();
  const { handler: hideHandler, stream: hide$ } = createEventHandler();

  const modal$ = merge(
    toggle$.pipe(
      startWith(false),
      map(() => prev => !prev),
      scan((state, changeState: any) => changeState(state))
    ),
    show$.pipe(
      startWith(false),
      map(() => prev => true),
      scan((state, changeState: any) => changeState(state))
    ),
    hide$.pipe(
      startWith(false),
      map(() => prev => false),
      scan((state, changeState: any) => changeState(state))
    )
  );

  return combineLatest(prop$, modal$).pipe(
    map(([props, modal]) => {
      console.log(modal);
      return (
        <div>
          <button onClick={toggleHandler}>Toggle</button>
          <button onClick={showHandler}>Show</button>
          <button onClick={hideHandler}>Hide</button>
          <h1>{modal ? 'Visible' : 'Hidden'}</h1>
        </div>
      );
    })
  );
});

В этом примере toggle не учитывает текущее значение show или hide, а только свое собственное последнее значение.

https://stackblitz.com/edit/react-rxjs6-recompose

Ответы [ 3 ]

0 голосов
/ 20 января 2019

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

const { of, merge, fromEvent } = rxjs; // = require("rxjs")
const { map, scan } = rxjs.operators; // = require("rxjs/operators")

const toggle$ = fromEvent(document.getElementById('toggle'), 'click');
const show$ = fromEvent(document.getElementById('show'), 'click');
const hide$ = fromEvent(document.getElementById('hide'), 'click');

const reduce = (state, change) => change(state);

const initialState = false;
const state$ = merge(
  of(e => e),
  toggle$.pipe(map(e => state => !state)),
  show$.pipe(map(e => state => true)),
  hide$.pipe(map(e => state => false)),
).pipe(
  scan(reduce, initialState),
);

state$.subscribe(e => console.log('state: ', e));
<script src="https://unpkg.com/rxjs@6.2.2/bundles/rxjs.umd.min.js"></script>


<button id="toggle">Toggle</button>
<button id="show">Show</button>
<button id="hide">Hide</button>

Чтобы лучше понять, как это работает, взгляните на Создание приложений статья из документации rxjs

0 голосов
/ 22 января 2019

Я применил подход каждого и придумал это.Он сохраняет логику toggle () внутри функции карты и использует startWith () для установки значения.

  const modal$ = merge(
    toggle$.pipe(
      map(() => prev => !prev),
    ),
    show$.pipe(
      map(() => prev => true),
    ),
    hide$.pipe(
      map(() => prev => false),
    )
  ).pipe(
    startWith(false),
    scan((state, change) => change(state)),
  );
0 голосов
/ 20 января 2019

Сначала наличие startWith на всех этих наблюдаемых означает, что все они будут излучать в начале ложь.Как будто вы нажали все эти кнопки одновременно.

Я думаю, вы должны попытаться добиться другого поведения.Используя startWith, вы хотите установить начальное состояние свойства modal, верно?Следовательно, он должен появиться после объединения этих потоков.

Для переключения значения вам нужны две вещи:

  1. место, где хранится состояние (обычно аккумулятор scan)
  2. Различают эти нажатия кнопок.У вас есть три кнопки, поэтому вам нужно три значения.

Это мой подход:

 const modal$ = merge(
    show$.pipe(mapTo(true)),
    hide$.pipe(mapTo(false)),
    toggle$.pipe(mapTo(null))
  ).pipe(
    startWith(false),
    scan((acc, curr) => {
      if (curr === null) {
        return !acc;
      } else {
        return curr;
      }
    })
  );

Показать кнопку всегда выдает true, кнопка скрытия выдает false и кнопку переключенияиспускает null.Я объединяю их вместе, и мы хотим начать с false.Далее идет scan, который хранит состояние в аккумуляторе.

Когда приходит null, он возвращает отрицательное состояние.Когда приходит true или false, он возвращает его - таким образом он устанавливает новое состояние независимо от предыдущего значения.

...