Code Monkey home page Code Monkey logo

Comments (5)

josepot avatar josepot commented on June 20, 2024 1

My point is that an observable with shareReplay should have it's last (aka "stale") value available synchronously in the initial mount

Not necessarily, no. Just because an Observable has been enhanced with shareReplay, that doesn't guarantee that the Observable will emit synchronously. It will only emit synchronously if:

  1. It has previously emitted a value (while there were at least a one listener).
  2. After having emitted that first value at least one listener stayed subscribed by the time that the new subscription takes place.

However, the first value can come at any point in time, if it ever comes. So, yeah: just because an Observable has been created through the shareReplay enhancer, that doesn't mean that the observable will always emit synchronously.

My point is that an observable with shareReplay should have it's last (aka "stale") value available synchronously in the initial mount, and the fallback should never be rendered

Even if that was true (which it isn't), the only way to access that value is through a subscription, and since subscribing to an Observable it's a side-effect, it's something that can't be done on the render phase of the component. It can only be done after the component was mounted. That's b/c due to React concurrent-mode: a render function can be called on a component that will never be mounted (and thus never unmounted), and if that happen then we would be creating unnecessary side-effects and stale subscriptions. Therefore, there is no way to actually access the "current" value of a shareReplay Observable during the render function. That's why in this library we have had to come up with these StateObservables and other shenanigans, so that we can work around these short-comings (or trade offs, depends on who you ask) of React.

This is the stale-while-revalidate paradigm. It seems to me that react-rxjs is doing nothing-while-revalidate. If this isn't the goal of this library I understand.

We've most definitely failed at explaining the goals and the trade off of our library. Not your fault, of course. We should really improve our docs and explain these things better.

from react-rxjs.

josepot avatar josepot commented on June 20, 2024

Is there a way I can achieve this? Or is this a bug with Subscribe's initial state?

Of course! Just keep a subscription always open, and then it will always have the latest value in memory. I.e: subscribe to the observable, right after defining it.

from react-rxjs.

voliva avatar voliva commented on June 20, 2024

<Subscribe> always guarantees that it will have subscribed to the source observables before any of its children is rendered. This is something that's needed to prevent lingering subscriptions, specially with React with concurrent mode.

As mentioned in the docs:

It will subscribe to all the observables used by its children before they get mounted, and will unsubscribe from all of them once it unmounts.
IMPORTANT: This Component first mounts itself rendering null, subscribes to source$ and then it renders its children.

The way it does this is by first rendering nothing (or the fallback) on initial render, subscribing to the sources, and then rendering the children passed to it.

Not sure if it needs more clarification on the docs, or maybe an explanation on the actual implications of this.

If you want to avoid this double-render you'll have to manage the subscriptions further up: Don't use <Subscribe> at that level, instead declare an observable that will subscribe to all the streams your components need (a merge usually does the trick) when they are needed to become active, and subscribe to this observable further up on your tree.

from react-rxjs.

pkpbynum avatar pkpbynum commented on June 20, 2024

I think I understand the points you both are making. My point is that an observable with shareReplay should have it's last (aka "stale") value available synchronously in the initial mount, and the fallback should never be rendered. It should render the stale value until the next value is observed. This is the stale-while-revalidate paradigm. It seems to me that react-rxjs is doing nothing-while-revalidate. If this isn't the goal of this library I understand.

To @voliva's point, I'll try to raise my Subscribe up my react tree, but I think this isn't quite the behavior I want. If I do that, then the subscription's lifetime is no longer tied to where the data is needed in the react tree. Also--if I understand correctly--if there's an error, I'd need to remount that entire tree to start the subscription again.

from react-rxjs.

voliva avatar voliva commented on June 20, 2024

To @voliva's point, I'll try to raise my Subscribe up my react tree, but I think this isn't quite the behavior I want. If I do that, then the subscription's lifetime is no longer tied to where the data is needed in the react tree. Also--if I understand correctly--if there's an error, I'd need to remount that entire tree to start the subscription again.

In theory it's posible to do the same behaviour you want, without relying on React's render cycle, but it's more tedious than just using <Subscribe> on the place you wanted.

<Subscribe> has this limitation that it will do that double render. In some cases that's not bad, but on others it is annoying... and the solution is to not use Subscribe there. You can move it to the nearest place where it doesnt get unmounted/remounted, and declare how that subscription is managed passing in the source$ prop.

I've modified your sandbox to better show you what I mean: https://codesandbox.io/s/elegant-feather-fw2vjs?file=/src/App.tsx
On these cases it gets more tedious, as React-RxJS currently can't really circumvent the limitations of React when it comes to execution of side-effects (such as creating a subscription).

If you need error handling, this is something you can also add to your custom subscription management. For this, retry({ delay: () => anotherObservable$ }) is usually very useful: It prevents the error from being propagated into the <Subscribe>, and re-subscribes to the observable when you declare it to.

Edit --- I forgot to mention that there's another alternative which sometimes can also work (in your sandbox it does). You can remove the fallback from Subscribe and just add a suspense boundary inside:

  const content = toggle ? null : (
    <Subscribe>
      <Suspense fallback="wait...">
        <TodoList />
      </Suspense>
    </Subscribe>
  );

Subscribe will still do the double render, but in this case it will render nothing on mount, so the user won't see the fallback "Wait..." for that split second. This is just to say most of the time this behaviour is not noticeable, but there are some cases where it does matter. For those ones, it's better to just declare how your subscriptions are managed through another observable.

from react-rxjs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.