re-rxjs / react-rxjs

React bindings for RxJS
https://react-rxjs.org
MIT License
542 stars 17 forks source link

`<Subscribe>` without `source$` does not seem to work as advertised #308

Closed justbhoot closed 10 months ago

justbhoot commented 10 months ago

The documentation here says:

Subscribe also subscribes to all the observables used by its children (as if it were a React's Context), so in this case we can just omit source$

Keep in mind that will hold a subscription to the observables until it gets unmounted, ...

But the above does not seem to work.

I have set up a GitHub repo to demonstrate the issue: https://github.com/jyssh/react-rxjs-subscribe-problem/.

To run the repo, do npm ci followed by npm run dev. Alternatively, this codesandbox should run the app right away.

As described in the repo's README:

<Subscribe> wraps two screens - <SelectCropScreen> and <One>. Check the Yield.jsx file to verify. So any subscriptions made in both these screens - <SelectCropScreen> and <One> - should have been retained. But that does not happen. <Subscribe source$> works as intended though.

voliva commented 10 months ago

That same paragraph starts with a key point:

If you don't give it a default value, you will need to make sure that observable has a subscription active before the Component that uses that hook is called.

The behaviour that <Subscribe> has regarding auto-subscribing only applies for those states that don't have a default value.

In cases where the state does have a default value, the component doesn't require an active subscription to that state during rendering. Consequently, <Subscribe> will not subscribe to it.

If you do require an open subscription for that state, you can make use of the source$ parameter, as you've already noted.

justbhoot commented 10 months ago

Ok. My use case is a multi-step (or multi-"page") form, throughout which I need to keep several state-streams - each associated with an input - alive.

However, the components subscribed to those state-streams would come and go as the form changes its step/page. But I would like to those state-streams retain their values and not reset to 0 (when the subscriptions to them reach 0).

I see <Subscribe> as a way to keep subscriptions to those streams alive while the page under the <Subscribe> keep switching.

Is this way of using <Subscribe> correct?

If not, then is there another way to achieve my purpose?

justbhoot commented 10 months ago

If you do require an open subscription for that state, you can make use of the source$ parameter, as you've already noted.

If <Subscribe source$> is the only way, then in order to keep more than 1 state-streams alive, I imagine I would have to merge those streams into one, and use that merged stream as the source$. Correct?

voliva commented 10 months ago

If <Subscribe source$> is the only way, then in order to keep more than 1 state-streams alive, I imagine I would have to merge those streams into one, and use that merged stream as the source$. Correct?

Yes, exactly. The auto-subscribing feature of Subscribe was added in the 0.8.0 release. Before that, you would have to merge all of your streams and pass them manually to the source$.

After 0.8.0 source$ became optional, and it works great for the vast majority of cases. However, there are still some cases where you still need to manage your subscriptions manually... Either because you want to activate them regardless if a component is mounted or not, or to avoid the double-render that Subscribe does when mounting for the first time (and maybe other cases I haven't found yet).

justbhoot commented 10 months ago

Yes, the merged stream would involve some maintenance.

and maybe other cases I haven't found yet

I think my usecase would qualify too - maintain a stream of an input value. I would have to pass a default value of empty string "" to bind. Otherwise, <Subscribe> would just stick to using the fallback component; there would be no value passing into the stream without the input component loading.

So in this case, I guess passing default value to bind is necessary. So I would have to use a merged source$.

If there is another way, then I would appreciate any pointers.

On Thu, 7 Sep 2023, at 19:38, Victor Oliva wrote:

If <Subscribe source$> is the only way, then in order to keep more than 1 state-streams alive, I imagine I would have to merge those streams into one, and use that merged stream as the source$. Correct?

Yes, exactly. The auto-subscribing feature of Subscribe was added in the 0.8.0 release. Before that, you would have to merge all of your streams and pass them manually to the source$.

After 0.8.0 source$ became optional, and it works great for the vast majority of cases. However, there are still some cases where you still need to manage your subscriptions manually... Either because you want to activate them regardless if a component is mounted or not, or to avoid the double-render that Subscribe does when mounting for the first time (and maybe other cases I haven't found yet).

— Reply to this email directly, view it on GitHub https://github.com/re-rxjs/react-rxjs/issues/308#issuecomment-1710221532, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAOTU46PXNHAZXM2KE4NIPLXZHIMVANCNFSM6AAAAAA4OMBB4Q. You are receiving this because you authored the thread.Message ID: @.***>

voliva commented 10 months ago

You can also do bind(someObservable$.pipe(startWith("")))

justbhoot commented 10 months ago

That works! Thank you for this library and your prompt response.