question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Subscribing in render phase is not "safe"

See original GitHub issue

In the same vein as my concerns in https://github.com/kosich/react-rxjs-elements/issues/4 I walked through your library to see how it works, it is very clever!

However, I see that in render phase, the library is calling toPromise (essentially subscribing in render). Would it be accurate to say that the way this library works is as following:

  • User calls connectObservable causing their stream to gain a monkey patched getValue() method
  • React renders the hook for consuming your stream, internally it passes an init thunk to useReducer
  • This init thunk is invoked by react, in the render phase, which calls getValue()
  • getValue causes the stream to become subscribed (it calls toPromise())
    • this happens in render phase
    • a 200ms timeout is set to unsubscribe…
  • If React commits, the useEffect hook runs, and subscribes a second time (to the shared observable, so the source stream is only subscribed once)
  • If react doesn’t commit until 201ms, the first subscription will be destroyed by the timeout, and theuseEffect hook will run causing a second subscription (to a new instance of a shared observable, so the source stream is subscribed twice as well)

Is this all correct? If subscribing to a stream triggers side effects like a network request, this could be really important to users for it to be documented as a tradeoff the library makes, so they can know this upfront instead of learning it the “hard way” after writing an app.

If I understand, there is a tradeoff here where:

  • lowering the timeout can increase the chances of duplicate side effects
  • increasing the timeout will mitigate the affordance where the library is intending to solve for “memory leaks” (if react is aborting renders fast enough there could be enough back pressure to cause memory leaks depending how high the timeout is set & how fast react is aborting renders)
  • if a render phase in react takes over 200ms before it commits, effects will be double subscribed

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
joshribakoffcommented, Aug 30, 2020

@voliva thats correct the App component (sorry for the terrible names) is mounting and un mounting App2 as a “low priority” update and is just setting some other arbitrary higher priority state which sometimes interrupts the lower priority update causing App 2 to render and “abort” or “miss” the mount/unmount

I would say your very detailed description above clarifies the tradeoffs such that users can reasonably use it safely (although I’m personally leaning towards being against this idea of side effects in render phase in my library)

Thanks for the detailed response if you need anyone to bounce ideas off of or review the docs feel free to ping me and best of luck with it all!

1reaction
joshribakoffcommented, Aug 30, 2020

Hey, I’m sorry if my comment came off as a blatant order or unsolicited advice. Looking forward to the docs

Read more comments on GitHub >

github_iconTop Results From Across the Web

Gotchas - Observable Hooks
If you are not sure or are having issues, use useLayoutSubscription which establishes subscription synchronously after the render phase and before browser ...
Read more >
Is it safe to change a ref's value during render instead of in ...
The documentation for React Strict Mode leads me to believe that performing side effects in render() is generally unsafe.
Read more >
What should we do with the warning "Cannot update ... - GitHub
In CM this initial "render" can be interrupted and thrown away so it's not safe. It "may" work as it is right now...
Read more >
Subscriptions With React Hooks - Medium
Even better, it's far more reliable than the old code and we don't have to store a reference to unsubscribe in our state....
Read more >
Update on Async Rendering – React Blog
In practice this was never true because React has always executed render immediately after componentWillMount . If the data is not available by ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found