-
Notifications
You must be signed in to change notification settings - Fork 107
/
Copy pathComputedStateComponent.cs
79 lines (64 loc) · 3.41 KB
/
ComputedStateComponent.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
using Stl.Fusion.Blazor.Internal;
using Stl.OS;
namespace Stl.Fusion.Blazor;
public static class ComputedStateComponent
{
private static readonly ConcurrentDictionary<Type, string> StateCategoryCache = new();
public static ComputedStateComponentOptions DefaultOptions { get; set; }
static ComputedStateComponent()
{
DefaultOptions = ComputedStateComponentOptions.SynchronizeComputeState
| ComputedStateComponentOptions.RecomputeOnParametersSet;
if (HardwareInfo.IsSingleThreaded)
DefaultOptions = ComputedStateComponentOptions.RecomputeOnParametersSet;
}
public static string GetStateCategory(Type componentType)
=> StateCategoryCache.GetOrAdd(componentType, static t => $"{t.GetName()}.State");
public static string GetMutableStateCategory(Type componentType)
=> StateCategoryCache.GetOrAdd(componentType, static t => $"{t.GetName()}.MutableState");
}
public abstract class ComputedStateComponent<TState> : StatefulComponentBase<IComputedState<TState>>
{
protected ComputedStateComponentOptions Options { get; init; } = ComputedStateComponent.DefaultOptions;
// State frequently depends on component parameters, so...
protected override Task OnParametersSetAsync()
{
if ((Options & ComputedStateComponentOptions.RecomputeOnParametersSet) == 0)
return Task.CompletedTask;
_ = State.Recompute();
return Task.CompletedTask;
}
protected virtual string GetStateCategory()
=> ComputedStateComponent.GetStateCategory(GetType());
protected virtual ComputedState<TState>.Options GetStateOptions()
=> new() { Category = GetStateCategory() };
protected override IComputedState<TState> CreateState()
{
// Synchronizes ComputeState call as per:
// https://github.com/servicetitan/Stl.Fusion/issues/202
var stateOptions = GetStateOptions();
Func<IComputedState<TState>, CancellationToken, Task<TState>> computer =
(Options & ComputedStateComponentOptions.SynchronizeComputeState) == 0
? UnsynchronizedComputeState
: stateOptions.FlowExecutionContext && DispatcherInfo.IsExecutionContextFlowSupported(this)
? SynchronizedComputeState
: SynchronizedComputeStateWithManualExecutionContextFlow;
return new ComputedStateComponentState<TState>(stateOptions, computer, Services);
Task<TState> UnsynchronizedComputeState(
IComputedState<TState> state, CancellationToken cancellationToken)
=> ComputeState(cancellationToken);
Task<TState> SynchronizedComputeState(
IComputedState<TState> state, CancellationToken cancellationToken)
=> this.GetDispatcher().InvokeAsync(() => ComputeState(cancellationToken));
Task<TState> SynchronizedComputeStateWithManualExecutionContextFlow(
IComputedState<TState> state, CancellationToken cancellationToken)
{
var executionContext = ExecutionContext.Capture();
var taskFactory = () => ComputeState(cancellationToken);
return executionContext == null
? this.GetDispatcher().InvokeAsync(taskFactory)
: this.GetDispatcher().InvokeAsync(() => ExecutionContextExt.Start(executionContext, taskFactory));
}
}
protected abstract Task<TState> ComputeState(CancellationToken cancellationToken);
}