-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
useObservableEagerState missing emit #86
Comments
What does your observable look like? As the docs stated, |
They are all BehaviorSubjects. But are being provided as Observables. Here is an example.
accessible publically ONLY via an accessor that returns a SINGLE NEVER CHANGING observable instance:
|
Let me try to state the sequence of events I believe is happening:
|
Don't know how the
Base on your description, if " observable-hooks/packages/observable-hooks/src/use-observable-eager-state.ts Lines 33 to 43 in 0e4feeb
If not, then it means the |
|
I haven't gotten around to creating a standalone example-- but in lieu, let me respond to some points.
It is the BehaviorSubject implementation from rxjs. https://github.com/ReactiveX/rxjs/blob/master/src/internal/BehaviorSubject.ts
The The point is you can't guarantee that the value hasn't changed between the time the
On one hand, you could argue that functional components shouldn't be creating "side effects" during their execution. But on the other hand, the point of using Observables is to manage asynchronous events or side-effects. Observables present a asynchronous-like contract, but its actual implementation is largely (entirely?) synchronous.
The problem with I hope to get you a reproducible example sometime! |
If observable-hooks/packages/observable-hooks/src/use-observable-eager-state.ts Lines 59 to 81 in 60fc8e1
Synchronous values has been captured from the first subscription, that's why we need to skip values from the second one. observable-hooks/packages/observable-hooks/src/use-observable-eager-state.ts Lines 31 to 45 in 60fc8e1
This is not about the observable design pattern but how
Unfortunately because React introduces concurrent mode, we cannot perform synchronous side effects safely. The obserjvable subscription has to happen asynchronously. For
|
I tried to recreate my problem, but am having a hard time understanding a certain behavior. Perhaps you can explain it to me. Clone https://github.com/Paitum/eager-app then run To reproduce the behavior, I am purposely emitting a new value immediately after the
I can't reproduce the problem, because the So how is the state being set to the newly-emitted value of "Final Value" here: https://github.com/Paitum/eager-app/blob/main/src/use-observable-eager-state.js#L56 ? |
This is because you had strict mode enabled and performed side effects during React rendering. React is hacking the |
Thanks. I just used the react create app and it added that. Although Strict must be doing more than hacking console.log, since the behavior changed as well. Ok, so now when I run it without StrictMode, I see the problem that I was trying to reproduce. The result is "The value is Initial Value" gets rendered. Now we can have a conversation about "correctness". Let me explain my architecture first. My application uses a "Service Context", that can provide any component with any service instance via a hook, like A pattern we setup is for the service to automatically fetch data ONLY WHEN an observable accessor is requested. So, the Any given component SHOULDN'T know whether a service function or accessor will have a side-effect. That's the point of using observables. And each service shouldn't need to add any unnecessary logic to support UI constraints-- like making something asynchronous ala So that's why I'm wondering why the implementation of |
Thanks for the code!
Yes, hooks are invoked twice in strict mode. They try to hide that with hacking
The pattern you described is very much similar to React's Suspense pattern IMO. With observable-hooks you can easily implement this kind of Stale-While-Revalidate pattern. A more "Rx" way to achieve this is to make a cold observable that connects to the BehaviorSubject for result-check or triggering side effects. const fetchData = () => {
console.log('start fetching...')
return new Promise(resolve => {
setTimeout(() => {
resolve('Final Value')
}, 2000)
})
}
function Service() {
const subject$ = new BehaviorSubject('Initial Value');
let fetched = false
const observable$ = new Observable(subscriber => {
if (!fetched) {
fetched = true
fetchData()
.then(value => subject$.next(value))
.catch(error => subject$.error(error))
}
return subject$.subscribe(subscriber)
});
return {
get value$() {
return observable$;
}
}
}
const serviceInstance = new Service()
serviceInstance.value$.subscribe(v => console.log('subscription1', v))
serviceInstance.value$.subscribe(v => console.log('subscription2', v))
Back to the code, the |
observable-hooks@4.1.1 published which fixes this issue. |
I have a Preact app that is using observables for state and use observable-hooks library to update components.
The problem I am facing is with
useObservableEagerState
missing important emits. I have a specific scenario involving a mouse-over component and backend call-- both of which are asynchronous to the lifecycle, that renders the component with the INITIAL value, but then misses the backend call's data from the second emit of the observable.I have tracked this down to this line:
https://github.com/crimx/observable-hooks/blob/master/packages/observable-hooks/src/use-observable-eager-state.ts#L65
I can see that my observable is emitting the data within this useEffect-subscription, but it is being ignored because
isAsyncEmissionRef.current
isfalse
.I understand that this logic is there to protect against
triggering extra initial re-rendering
, but if it is "swallowing" a value, then that isn't desirable either.Shouldn't this function guarantee that the synchronous values not be ignored? Something along the lines of:
The text was updated successfully, but these errors were encountered: