-
-
Notifications
You must be signed in to change notification settings - Fork 44
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
Operator proposal: defer
#329
Comments
I've added implementation draft: #330 If proposal would be approved I'll add tests and docs there |
In our codebase we use this simple operator: export function postpone<T>({
clock,
until,
target,
}: {
clock: Event<T>
until: Store<boolean>
target: Event<T>
}): Event<T> {
return sample({
clock: [clock, until],
source: clock,
filter: until,
target,
})
} Looks like you are proposing the same? |
If i got it right your operator calls the You can check the details in implementation draft PR |
This operator would be useful to me. Here's the use case I have: I have a store that often receives updates, every new update basically invalidates the previous states. I want to process these updates using an asynchronous effect, but to avoid calling the processing effect too many times, I would like to defer processing a new update until the processing of the old update is finished. It's almost the same logic as This cannot be achieved using the method proposed above because my store is not a one-off, so the event will be called repeatedly. |
Copy-pasted the operator from the PR, works great. Here's the solution that worked for me: const treeChanged = debounce(vfs.$tree, 500)
const runRulesFx = createEffect(runRules)
sample({
clock: defer({ clock: treeChanged, until: not(runRulesFx.pending) }),
source: vfs.$tree
target: runRulesFx,
}) The |
Motivation
Web is asynchronous by it's nature and there are a lot of cases when we wait for something, defer/postpone something and so on.
Let's assume we have a user that want to pay using his wallet created in our app. He asks us how to do it and we want to give him an url that either will open wallet creation or wallet details depending on whether he already created the wallet or no.
Both of wallet creation and wallet details are dialogs belonging to the pay page. Existence of the wallet is checked by the request inited by pay page and buttons that open this dialogs are disabled until data is loaded. Everything worked pretty well until we decided to give user a direct url that opens one of these dialogs. The problem is that the data needed to determine what dialog to open is still loading.
Sure we can just rework our UI to have one dialog that shows loading until data is loaded and renders different contents despite these dialogs are not related at all but the essence of the problem is that we have a synchronous event of opening our url and want to handle it asynchronously. In imperative API like effect handler we can do it with ease using async/await but there is no solution for declarative API
Solution
Since almost everything is asynchronous in web, sometimes we want to handle events asynchronously. In imperative API like effect handler we can do it with ease using async/await, but there is no solution for declarative approach. We can rely on effect's done/fail events to call event after an asynchronous action but this works only in case when we have
event -> effect -> another event
chain. There is a case when event doesn't trigger effect but depends on data fetched by it. Effect in the other hand is called by another trigger.In this case we have two branches of code:
That is where
defer
operator comes in.You can read this as "when event is happened check if $itCanBeHandled is true. If so call the handleEventFx. If no wait until $itCanBeHandled became true and then call handleEventFx.
Let's try to solve the problem described in motivation. We want to open either wallet creation or wallet details dialog depending on whether wallet exists by direct url
In this case we will run the split only when $wallet be ready to determine what dialog should be opened.
Details
If clock will be called more than 1 time only the last event will be deferred and called. Other events will be ignored
The text was updated successfully, but these errors were encountered: