-
Notifications
You must be signed in to change notification settings - Fork 19
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
Preferred way to represent "not yet known" value #85
Comments
Hi, https://sutil.dev/#examples-await-blocks That's interesting to read about BehaviorSubject. Store does have an initial value, but you're right that as soon as you start projecting and filtering, you end up with IObservable. (Store does guarantee to send the initial value out to any new subscribers though) Here are the Bind.promise functions: static member promises (items : IObservable<JS.Promise<'T>>, view : 'T -> SutilElement, waiting: SutilElement, error : Exception -> SutilElement)=
Bind.el( items, fun p -> Bind.promise(p, view, waiting, error) )
static member promise (p : JS.Promise<'T>, view : 'T -> SutilElement, waiting: SutilElement, error : Exception -> SutilElement)=
Bind.el( p.ToObservable(), fun state ->
match state with
| PromiseState.Waiting -> waiting
| PromiseState.Error x -> error x
| PromiseState.Result r -> view r
)
static member promise (p : JS.Promise<'T>, view : 'T -> SutilElement) =
let w = el "div" [ CoreElements.class' "promise-waiting"; text "waiting..."]
let e (x : Exception) = el "div" [ CoreElements.class' "promise-error"; text x.Message ]
Bind.promise(p, view, w, e ) |
Thanks! I see you use a similar approach to the module Store =
let makeAsyncOption (x: Async<'T>) : IStore<'T option> =
let store = Store.make None
async {
let! result = x
result |> Some |> Store.set store
} |> Async.StartImmediate
store Suggested variant would be to use a custom store-like class implementing |
I'm open to this, but I need to understand why it would be desirable to have this extra code to maintain when we can already implement Store<'T> with 'T = Option<'U> |
It is more about what is the behavior of One could take advantage of this behavior and use it for "value not yet available". The extensions which would allow more user-friendly API (creating stores without initial value, having On the other hand, this means any current and future usages of edit: typos |
I see. It's not so much about the way Store behaves, but consumers of IObservable. It's true that in Sutil, I know that when I'm handed an IObservable, and subscribe to it, that I will immediately receive the initial value (because of the way Store works, which I modelled on Svelte's stores/cells). Would it be useful then to have overloads of Bind.el (et al) like the following? // Current signature (or at least, very close to it
Bind.el( data : IObservable<'T>, view: 'T -> SutilElement )
// Using Option
// view None will be shown until a value arrives
Bind.el( data : IObservable<'T>, view: 'T option -> SutilElement )
// Without Option, using init/view pair
// init() will be shown value arrives
Bind.el( data : IObservable<'T>, init: unit -> SutilElement, view: 'T -> SutilElement ) Option feels more canonical, but I don't like that we have to wrap every value in Some just to handle an initial case. Regardless of that small point, am I addressing the issue you're raising? Cheers |
Yes, it's exactly what I had in mind. Sorry it took me several posts to make myself clear :) Unless you have some prior objections to the suggested behavior, I'll test it in one of my projects to see how it performs in real scenarios. Then you should be able to write something like: let store : IObservable<_> = getDataAsync() |> DelayedStore.makeAsync
// ...
Bind.el(store, (fun () -> Html.text "Loading...."), (fun data -> Html.text $"Data received: {data}")) |
Hi,
What is the canonical way to represent "not yet known" value? For example, result of an async expression?
The simplest way (achievable now) is to simply use
Store<T option>
.Stores and their derivations are implementations of
IObservable<T>
, which do not guarantee that values are always present (that is, the observable is not "behavior subject", as described here. This would most likely work with current functions (e.g.Bind.el
), however, there is no way to represent "loading" state (or is there?). A possibility would be to add a new function overload withloader
element to be displayed when value is not available yet.What are your thoughts on this?
The text was updated successfully, but these errors were encountered: