Recompose: How could I have mapPropsStreamWithConfig use BehaviorSubject

Created on 14 Jun 2017  路  9Comments  路  Source: acdlite/recompose

Is it possible to do this? I see mapPropsStreamWithConfig takes has a fromESObservable, but I can't initialize it with the first props, so I'm force to use {}, which is not the right solution:

const config = {
  fromESObservable: x => new BehaviorSubject({}),
  toESObservable: stream => stream,
};

Most helpful comment

Thanks for helping me with this. My suggestion does seem a little off. If I have a few of these even handlers that need access to the props, such as when dispatching on an action, then I have a lot of withLatestFrom. Here's an example:

const enhance = mapPropsStream(props$ => {
  const props$$ = props$.shareReplay(1);

  const {
    handler: fetchResult,
    stream: fetchResult$
  } = createEventHandler();

  const result$ = fetchResult$
    .withLatestFrom(props$$, (request, props) => ({ request, props }))
    .switchMap(({ request, props }) => fakeSuccess(props.id).catch(x => {
      props.actions.notify('whoops');
      return Observable.of('bad');
    }))
    .startWith('loading');

  return props$$.combineLatest(result$.startWith(0), (props, result) => ({
    ...props,
    fetchResult,
    result
  }));
});

Full: https://gist.github.com/fingermark/03bdda722a314ff75cfd5d30c5c2ecd8

Edit:

I was wondering if there was an easier option, such as using a BehaviorSubject, where I could just call getValue() on it, instead of adding withLatestFrom each time. And, if so, how I could do that.

All 9 comments

Without it, I have to use shareReplay(1) and withLatestFrom pretty much any operation that needs access to a prop, such as props.someAction or props.mainId

I'm not understand at all what are you want to achieve.
Why not to skip first props or/and intialize BehaviourSubject not in config function?

BTW you need something like

fromESObservable: x => Observable.from(x).skip(1).startWith(INITIAL).shareReplay(1)

even I can't recommend using config like above

Thanks for helping me with this. My suggestion does seem a little off. If I have a few of these even handlers that need access to the props, such as when dispatching on an action, then I have a lot of withLatestFrom. Here's an example:

const enhance = mapPropsStream(props$ => {
  const props$$ = props$.shareReplay(1);

  const {
    handler: fetchResult,
    stream: fetchResult$
  } = createEventHandler();

  const result$ = fetchResult$
    .withLatestFrom(props$$, (request, props) => ({ request, props }))
    .switchMap(({ request, props }) => fakeSuccess(props.id).catch(x => {
      props.actions.notify('whoops');
      return Observable.of('bad');
    }))
    .startWith('loading');

  return props$$.combineLatest(result$.startWith(0), (props, result) => ({
    ...props,
    fetchResult,
    result
  }));
});

Full: https://gist.github.com/fingermark/03bdda722a314ff75cfd5d30c5c2ecd8

Edit:

I was wondering if there was an easier option, such as using a BehaviorSubject, where I could just call getValue() on it, instead of adding withLatestFrom each time. And, if so, how I could do that.

Got you, I had the same issues, and initially used some kind of BehaviorSubject with getValue (explicitly putting latest props in closure variable), decided to not use that as I feel that such style is not in the nature of rx and some kind of escape hack.
Then started to use near the same withLatestFrom solution you provided.
Also used a solution to redefine handler at combineLatest to inject props into arguments - ie, fetch: (...args) => fetch(props, ...args) but it breaks possible optimizations.
Now if it possible I inject props using withHandlers enhancer, or use withLatestFrom solution above, not sure more easy solution exists. Im also interested how others solves this.

I've just come up with an idea if we don't mind to provide another util function.

const {
  handler,
  stream
} = createEventHandlerWithProps(
  props$, 
  // a function which should reduce the latest props and the value from the stream to a single value
  (props, value) => ({ ...props, value })
);

stream.subscribe((value, ...props) =>
  /* use you props and value here*/
  console.log(value) // 1
)

stream.next(1)

Not a bad suggestion. I just decided to revisit this and happened to check the code to see if createEventHandler took in something similar.

@fingermark Currently, createEventHandler doesn't take any argument, so you need to implement this function by youself.

@fingermark I'm running into a similar barrier to yours when trying to combine recompose with an interesting state management library focal from Grammarly. They use an atom to store state which is an implementation of BehaviorSubject with some special subclasses that allow it to act as an immutable, but modify-able single-source-of-truth鈩笍 (with lenses).

Does anyone from the thread have any emergent best-practices that might be helpful for using BehaviorSubjects with recompose?

Old issue but is there a way to use BehaviorSubject() with recompose()?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cdomigan picture cdomigan  路  4Comments

SeanGroff picture SeanGroff  路  4Comments

uriklar picture uriklar  路  4Comments

istarkov picture istarkov  路  3Comments

franklinkim picture franklinkim  路  3Comments