crimx/observable-hooks

Execute twice when use useObserveableState & useSubscription together

FailLone opened this issue · 7 comments

Steps to reproduce

  1. useObservable
const value$ = useObservable(input$ => input$ |> switchMap([v] => ajax(...)), [props.value])
  1. useObservableState
const value = useObservableState(value$)
  1. useSubscription
useSubscription(value$, v => props.onChange(v))

What is expected?

just request once

what is actually happening?

request twice

Actually, this will happen when using useObserveableState & useObservableCallback together, too.

crimx commented

useObservableState is a sugar for useSubscription.

crimx commented

What did you want to achieve?

If you need a state and also report to props you can either:

  • share at the end of the stream to make it hot.
  • Or useState then do setState and invoke props callback in useSubscription.
  • Or useObserveableState then useEffect to watch state changes and invoke props callback.

It depends on whether or not you want to react to initial sync state changes which are skipped in useObserveableState.

So, that's not a bug.
Thanks for your carefully answers!
BTW, is it a good practice invoking props callback in useObservable? like:

useObservable(input$ => input$ |> tap(([v]) => props.onChange(v)))
crimx commented

Yes. Callbacks in useObservable always reference to the latest context so it's safe to access states and props.

Sorry I misread. I meant useSubscription. It's not safe to do that in useObservable because the init callback is called only once which means the props callback you were referring to could be staled.

crimx commented

You should not do that in useObservable.

It's a amazing project!
Thanks again!