mrpmorris / fluxor Goto Github PK
View Code? Open in Web Editor NEWFluxor is a zero boilerplate Flux/Redux library for Microsoft .NET and Blazor.
License: MIT License
Fluxor is a zero boilerplate Flux/Redux library for Microsoft .NET and Blazor.
License: MIT License
Hello,
I'm brand new with Fluxor, so please forgive me if I'm doing something stupid.
I'm trying to follow the first tutorial, and am getting a compilation error.
I added the package, then added the following two lines to the ConfigureServices
method in Startup.cs
...
services.AddScoped<App>();
services.AddFluxor(o => o
.ScanAssemblies(typeof(Program).Assembly));
I know the tutorial says to put them in Program.cs
, but it didn't seem to make any difference, and everything else I've seen says to add your services in Startup.cs
I then added a class called App
and copied in the code. At this point, I tried to run the project, but had an error in the browser window of "No parameterless constructor defined for type 'FluxorTest.App'" which makes sense, as there isn't one.
What did I do wrong? Thanks
At the moment Fluxor detects self-inflicted endless loop and breaks out of the cycle. This loop started to happen once Effects were executed within a task (so that exceptions could be caught without holding up the pipeline).
In previous versions the routing middleware was able to check the browser's current URL against state and only dispatch an action if it is different, and this was sufficient because although effects can be async, the routing middleware's effect didn't await so executed synchronously.
Now that effects are all run inside an awaited task, this cannot happen synchronously, so by the time the middle checks the state against the current URL the URL could have changed due to an auth redirect to a sign-in page. At which point the middleware updates the browser URL, taking us back to the app, at which point the auth redirects us back to the sign-in page, ad ininitum.
Change the effects dispatcher so it executes each task outside of the Task.Run
(capturing any exceptions to a list), and then only run the Task.WhenAll
inside the Task.Run
. This will give synchronous effects the opportunity to run and complete immediately.
Hi @mrpmorris
I plan to write a book in french for Blazor.
In a dedicated chapter, I want to talk about Redux pattern and how to use it with Blazor.
As I'm currently using Fluxor for a project, my editor needs me to ask : can I speak about Fluxor in my book and how to use it ?
Thanks for answering !
In a Blazor WASM project, I am trying to handle the navigation to a new page once my HTTP method has completed successfully. My thinking is that I can then choose to remain on the page if I need to handle errors in the API call etc.
Using SubscribeToAction works unless I add a navigation call in the callback.: e.g.
SubscribeToAction<AddItemResponseAction>(x =>
{
NavigationManager.NavigateTo("/");
});
With the navigation call in place, I get Unhandled exception rendering component: Collection was modified; enumeration operation may not execute.
The exception is thrown by the line in the Notify method of the ActionSubscriber class (line #38):
foreach (Action<object> callback in callbacks)
If I change the previous Select query to persist (i.e. by adding a ToList() call), or change the foreach to foreach (Action<object> callback in callbacks.ToList())
, the exception is not thrown.
It doesn't seem resolvable by unsubscribing from the actions. Is there a way I can resolve this in client code rather than modifying the ActionSubscriber class?
Thanks.
I'd like to add an optional analyzer package for Fluxor that would contain various analyzers specific to the library to assist with keeping flux implementations clean and warning users about anti-flux patterns. I think a great starting point would be to add an analyzer that would warn consumers when they've added a set
er on one of their state classes to drive home the point that state should be immutable by nature.
Something akin to:
public class MyState
{
public string CurrentMessage { get; set; } // Would throw an analyzer warning to remove the setter
}
I'd like to get your thoughts on this and a possible viable approach, should you see it fit for the library. I was thinking something along the lines of adding an optional class attribute to intended state classes (i.e. [FeatureState]
, or something of the like) when you've added a package reference to the analyzer library. I believe Rider/ReSharper will do this by default for users as a refactoring, whereas this analyzer would be a specific warning that might keep you from compiling should you choose so, but I think this opens up the library to adding more specific analyzers for future use cases.
Hi, I'm trying to use Fluxor in combination with an API I wrote and Microsoft.Graph.
I'm getting this exception in the console:
WASM: Fluxor.Exceptions.StoreInitializationException: Store initialization error ---> System.NotSupportedException: The collection type 'Microsoft.Graph.IUserOwnedDevicesCollectionWithReferencesPage' on 'Microsoft.Graph.User.OwnedDevices' is not supported.
p.printErr @ blazor.webassembly.js:1
I need to get the members of an Azure AD Group and perform some operations on them.
Do you know if I need to set any parameter in order to be able to work with the Microsoft.Graph 3.0.1 nuget package?
In debugging an issue where state didn't appear to be affected by a dispatched action as expected following a page navigation, I found that an effects class (class with one or more methods marked [EffectMethod]) is instantiated twice. I'm new to Fluxor am not sure if this is expected, but it seems wrong. Is there any common mistake I could be making that would explain this behavior?
Most likely I don't completely understand how to share state between pages/components. I assumed that each time IState is injected into a component, it's always a reference to the same state object, so the state is already implicitly shared between pages. But maybe some special handling is required to accomplish this?
To reduce boilerplate it would be nice if it would be generated say with Source Generators by annotating the variable with annotation
Hi @mrpmorris,
I am using LiveSharp, a tool to rerender changes to the browser immediately. This tool sadly does not work with Fluxor at the moment.
I've reported the problem to the maintainer of LiveSharp, but he can't find the solution on his end, and it seems the problems lies in a missing try/catch when resolving assemblies with Fluxor. Is this something you can solve on your end?
More information can be found in the following issue: OYIon/LiveSharp#78
Still following the Blazor web tutorials (done the second one now), and I've noticed that when you click away from the counter page and then click back, the counter state is preserved, so if I click the button to increase the counter a few times, go to another page and come back, the number is the same as it was before, not reset to zero.
However, if I do the same with the fetch data page, the weather forecasts are reloaded. I noticed this as I was looking at what the IsLoading property was doing, and added a delay when loading the weather data. This allowed me to see the "Loading..." message, but also clarified that the data was reloaded every time I went back to the page.
How do I make it so that the weather data is also saved in the store and not reloaded? Thanks
I have a custom base class that implements basic parameter validation and awaits for the store to initialize (MyComponent < MyBaseClass < FluxorComponent). This base class has an IState<State>
property (not in MyComponent) and the components are not being refreshed.
Maybe something in the StateSubscriber, when calling GetStateDelegatesForType is not detecting properties in base classes?
Hi Fluxor team,
Just grabbed the latest .NET Preview 8 + Blazor, but Fluxor seems to failed on initialisation.
It works previously with .NET Preview 7.
I attached the stacktrace from the browser, but I'm not sure which part breaks. Hopefully this can help the team to debug it.
Any advice to get this working?
Thanks!
blazor.webassembly.js:1 Debugging hotkey: Shift+Alt+D (when application has focus)
blazor.webassembly.js:1 blazor Loaded 9.36 MB resourcesThis application was built with linking (tree shaking) disabled. Published applications will be significantly smaller.
blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Method has no body
System.BadImageFormatException: Method has no body
File name: 'Fluxor'
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure, Boolean allowClosed)
at System.Delegate.CreateDelegate(Type type, MethodInfo method, Boolean throwOnBindFailure)
at System.Delegate.CreateDelegate(Type type, MethodInfo method)
at Fluxor.Store..ctor()
at Fluxor.DependencyInjection.DependencyScanner.<>c__DisplayClass1_0.<RegisterStore>b__3(IServiceProvider serviceProvider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSiteMain(ServiceCallSite callSite, RuntimeResolverContext argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(ServiceCallSite callSite, RuntimeResolverContext argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__1(ServiceProviderEngineScope p)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[Store](IServiceProvider provider)
at Fluxor.DependencyInjection.DependencyScanner.<>c.<RegisterStore>b__1_2(IServiceProvider serviceProvider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSiteMain(ServiceCallSite callSite, RuntimeResolverContext argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(ServiceCallSite callSite, RuntimeResolverContext argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__1(ServiceProviderEngineScope p)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.AspNetCore.Components.ComponentFactory.<>c__DisplayClass6_0.<CreateInitializer>g__Initialize|2(IServiceProvider serviceProvider, IComponent component)
at Microsoft.AspNetCore.Components.ComponentFactory.PerformPropertyInjection(IServiceProvider serviceProvider, IComponent instance)
at Microsoft.AspNetCore.Components.ComponentFactory.InstantiateComponent(IServiceProvider serviceProvider, Type componentType)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateComponent(Type componentType)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateChildComponentOnFrame(RenderTreeFrame& frame, Int32 parentComponentId)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(DiffContext& diffContext, Int32 frameIndex)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(DiffContext& diffContext, Int32 frameIndex)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& diffContext, Int32 newFrameIndex)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, Int32 componentId, ArrayRange`1 oldTree, ArrayRange`1 newTree)
at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
f.printErr @ blazor.webassembly.js:1
f.preRun.push.window.Blazor._internal.dotNetCriticalError @ blazor.webassembly.js:1
_mono_wasm_invoke_js_unmarshalled @ dotnet.5.0.0-preview.8.20407.11.js:1
do_icall @ dotnet.wasm:1
do_icall_wrapper @ dotnet.wasm:1
interp_exec_method @ dotnet.wasm:1
interp_runtime_invoke @ dotnet.wasm:1
mono_jit_runtime_invoke @ dotnet.wasm:1
do_runtime_invoke @ dotnet.wasm:1
mono_runtime_try_invoke @ dotnet.wasm:1
mono_runtime_invoke @ dotnet.wasm:1
mono_wasm_invoke_method @ dotnet.wasm:1
Module._mono_wasm_invoke_method @ dotnet.5.0.0-preview.8.20407.11.js:1
call_method @ dotnet.5.0.0-preview.8.20407.11.js:1
set_task_result @ dotnet.5.0.0-preview.8.20407.11.js:1
(anonymous) @ dotnet.5.0.0-preview.8.20407.11.js:1
Promise.then (async)
js_to_mono_obj @ dotnet.5.0.0-preview.8.20407.11.js:1
f.preRun.push.window.Blazor._internal.getSatelliteAssemblies @ blazor.webassembly.js:1
_mono_wasm_invoke_js_unmarshalled @ dotnet.5.0.0-preview.8.20407.11.js:1
do_icall @ dotnet.wasm:1
do_icall_wrapper @ dotnet.wasm:1
interp_exec_method @ dotnet.wasm:1
interp_runtime_invoke @ dotnet.wasm:1
mono_jit_runtime_invoke @ dotnet.wasm:1
do_runtime_invoke @ dotnet.wasm:1
mono_runtime_invoke_checked @ dotnet.wasm:1
mono_runtime_try_invoke_array @ dotnet.wasm:1
ves_icall_InternalInvoke @ dotnet.wasm:1
ves_icall_InternalInvoke_raw @ dotnet.wasm:1
do_icall @ dotnet.wasm:1
do_icall_wrapper @ dotnet.wasm:1
interp_exec_method @ dotnet.wasm:1
interp_runtime_invoke @ dotnet.wasm:1
mono_jit_runtime_invoke @ dotnet.wasm:1
do_runtime_invoke @ dotnet.wasm:1
mono_runtime_try_invoke @ dotnet.wasm:1
mono_runtime_invoke @ dotnet.wasm:1
mono_wasm_invoke_method @ dotnet.wasm:1
Module._mono_wasm_invoke_method @ dotnet.5.0.0-preview.8.20407.11.js:1
call_method @ dotnet.5.0.0-preview.8.20407.11.js:1
(anonymous) @ dotnet.5.0.0-preview.8.20407.11.js:1
callEntryPoint @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
i @ blazor.webassembly.js:1
Promise.then (async)
u @ blazor.webassembly.js:1
i @ blazor.webassembly.js:1
Promise.then (async)
u @ blazor.webassembly.js:1
i @ blazor.webassembly.js:1
Promise.then (async)
u @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
r @ blazor.webassembly.js:1
v @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
n @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
(anonymous) @ blazor.webassembly.js:1
When implementing an effect, if you return from a sub-task with ConfigureAwait(false), you will be greeted with a lovely exception.
The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.
at Microsoft.AspNetCore.Components.Dispatcher.AssertAccess()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.AddToRenderQueue(Int32 componentId, RenderFragment renderFragment)
at Microsoft.AspNetCore.Components.ComponentBase.StateHasChanged()
at Fluxor.Blazor.Web.Components.FluxorComponent.<OnInitialized>b__3_0(IState _)
at Fluxor.Blazor.Web.Components.StateSubscriber.<>c__DisplayClass2_1.<Subscribe>b__1(Object s, EventArgs a)
at Fluxor.Feature`1.TriggerStateChangedCallbacks(TState newState)
at Fluxor.Feature`1.set_State(TState value)
at Fluxor.Store.DequeueActions()
at Fluxor.Store.Dispatch(Object action)
at ....my-project..../GlobalStore.cs:line 62
Simple Example:
[EffectMethod]
protected async Task HandleEffect(LoadAllTaskSettingsAction action, IDispatcher dispatcher)
{
try
{
dispatcher.Dispatch(new Update("Handling effect for LoadAllTaskSettingsAction"));
dispatcher.Dispatch(new Success(await _settings.GetAllSettingsAsync().ConfigureAwait(false)));
}
catch (Exception ex)
{
dispatcher.Dispatch(new Failure(ex));
}
}
Hi,
I would like to initialize some of my libraries in store initialization (or maybe I should use other place?), but this code is never run:
public class StoreInitializedEffect : Effect<StoreInitializedAction>
{
private readonly HttpClient HttpClient;
public StoreInitializedEffect(HttpClient httpClient)
{
HttpClient = httpClient;
}
protected override Task HandleAsync(StoreInitializedAction action, IDispatcher dispatcher)
{
dispatcher.Dispatch(new LanguagesFetchDataStoreAction());
return Task.CompletedTask;
}
}
ps. I love this library, but I had to write a lot of classes for CRUDs operations
When a component has subscribed to receive notifications of when specific actions are dispatched (IActionSubscriber
or FluxorComponent.SubscribeToAction
it is not possible to unsubscribe from all actions within the code that is called back.
Unfortunately, I don't have a lot of information available here, as the exception isn't really all that useful. At random times, we will receive an InvalidOperationException after executing an effect multiple times. It seems as though it's after the 2nd, 3rd, or 4th invocation of the same effect. (NOTE: the effect makes a couple of database calls, so everything is async using the new ConfigureAwait(false) fix)
I'm trying to come up with a reproduction case, and will update accordingly when I have a simplified version of one.
Exception Details:
System.InvalidOperationException
HResult=0x80131509
Message=DisposableCallback was not disposed
Source=Fluxor
StackTrace:
at Fluxor.DisposableCallback.Finalize()
Using Blazor Web (Server) and the 3.1.1 preview build.
Use case is that I have two booleans in my State, and I want to change one of them from true to false without changing the other (it should remember its previous value).
Problem is using the Reducers as explained in the docs one has to make a new state for every action, which forces me to set both booleans anew, so stakeholderExists will always be false after dispatching ReduceSetIsCreatableAction:
[ReducerMethod]
public static StakeholderState ReduceSetIsCreatableAction(StakeholderState state, SetIsCreatableAction action) =>
new StakeholderState(isCreatable: action.IsCreatable, stakeholderExists: false);
Is there any way I can change individual values and set the rest of the values from the previous state?
I would like to copy something from state to a local property so I can bind to it without modifying state directly. A later event will send the local copy back to state via an action.
If I use IState.StateChanged
to do this, I sometimes get a render before the StateChanged
event is fired. This makes mixing state with local properties problematic as it can produce scenarios not covered by tests.
For example, in the page below, the last paragraph should never show, but occasionally does.
@page "/customers/{id:int}"
@using Fluxor
@using FluxorGap.Data
@using FluxorGap.Store.EditCustomer
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
@if (State.Value.IsLoading) {
<p><em>Loading...</em></p>
}
else if (Customer != null) {
<p>Customer form here</p>
}
else {
<p style="color: red;"><strong>THIS SHOULD NEVER SHOW</strong></p>
}
@code {
[Parameter]
public int Id { get; set; }
[Inject]
private IState<State> State { get; set; }
[Inject]
private IDispatcher Dispatcher { get; set; }
private Customer Customer { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
State.StateChanged += StateOnStateChanged;
Dispatcher.Dispatch(new GetCustomerAction(Id));
}
protected override void Dispose(bool disposing)
{
if (disposing)
State.StateChanged -= StateOnStateChanged;
base.Dispose(disposing);
}
private void StateOnStateChanged(object sender, State state)
{
Customer = state.Customer?.Clone();
StateHasChanged();
}
}
Is there another way to copy state immediately after an effect?
Loving the library, good work.
This is probably PEBKAC but if you don't ask you don't know.
My parent component 'A', currently inherits my base component 'B'. I tried updating my base component 'B' to derive from your Fluxorcomponent but sadly It seems I have to directly inherit your Fluxorcomponent in my main component 'A', otherwise, nothing refreshes when the state changes. Why is this?
Do you have any examples of implementing when I can't inherit your FluxorComponent.
Some actions contain information that isn't destined for the store's state. For example, an effect that calls an API to return an editable object (e.g. Customer).
As the object is mutable it should not go into state where it can be modified. Instead, allow consumers to subscribe to the dispatching of actions so they can obtain a reference to the editable object for editing without it having to be reduced into state.
An example for observing dispatched actions in a component would look something like this
public class MyComponent : ComponentBase, IDisposable
{
[Inject]
protected IDispatcherObserver DispatcherObserver { get; set; }
private IDisposable Subscription;
protected override void OnInitialized()
{
base.OnInitialized();
Subscription = DispatcherObserver.Observe<GetForUpdateResultAction>(SetModel);
var getSupplierAction = new GetForUpdateAction(id: SupplierId);
Dispatcher.Dispatch(getSupplierAction);
}
void IDisposable .Dispose()
{
Subscription?.Invoke();
}
}
Or have a base Fluxor(some name)Component
protected override void OnInitialized()
{
base.OnInitialized();
Observe<GetForUpdateResultAction>(SetModel);
var getSupplierAction = new GetForUpdateAction(id: SupplierId);
Dispatcher.Dispatch(getSupplierAction);
}
private void SetModel(GetForUpdateResultAction action)
{
Model = action.Supplier;
StateHasChanged();
}
Brand new Fluxor user here, so I may be missing something obvious. I've been through the first Blazor web tutorial, and I think I understand pretty much what's going on, but have one point I can't work out.
When you dispatch an action, it seems that Fluxor looks around for a reducer method that matches the state and action types. For example, in the counter example there, you dispatch an IncrementCounterAction
and Fluxor looks for a reducer with a signature like this...
CounterState ReduceIncrementCounterAction(CounterState state, IncrementCounterAction action)
I understand how it knows to look for a reducer that takes the IncrementCounterAction
action type, as that is what was dispatched, but how does it know to look for a reducer with a CounterState
parameter? If I add another reducer with a different state type, it doesn't get called.
Please enlighten me ๐. Thanks
IDispatcher.Dispatch
documentation comment has a remarks
section about return type, which is no longer applicable (it's about Task, now it's void).
Fluxor/Source/Fluxor/IDispatcher.cs
Line 14 in c6067bc
Currently, [ReducerMethod]
decorated methods must have two parameters (State
and Action
). This lets Fluxor know which action type should trigger the method.
The problem is that if the action has no payload (and therefore isn't used within the reducer method) then the compiler will issue a warning that the parameter is not used and suggest it may be removed.
Allow the developer to specify the action type in [ReducerMethod]
so they can omit the Action
parameter.
// Currently
[ReducerMethod]
public static CounterState Reduce(CounterState state, IncrementCounterAction action) =>
new CounterState(state.Counter + 1);
// Additional supported format
[ReducerMethod(typeof(IncrementCounterAction))]
public static CounterState Reduce(CounterState state) =>
new CounterState(state.Counter + 1);
Hi,
I've a razor page like this
@inject IDispatcher Dispatcher
<form action="/">
<input @bind="_email" type="text" placeholder="Enter your email">
<input @bind="_password" type="password" placeholder="Enter your password">
<button @onclick="OnSignIn">Sign In</button>
</form>
@code{
public string _email {get;set;}
public string _password {get;set;}
public void OnSignIn ()
{
Dispatcher.Dispatch(new LoginAction(_email,_password));
}
}
While debugging I realised the Dispatcher.Initialized.Status was WaitingForActivation on the init, but will turn to RanToCompletion when the OnSignIn function is fired. And on the Effect file I cannot handle an async request to the back-end as the Task is complete.
What should I do to avoid this?
In the following code, when i click the submit button, it toggles between 2 states:
Visible: T F F
and
Visible T T T
The initial state in the store is T F T.
This causes Links for Second and Third steps to toggle between active and inactive.
Observations:
So why am i seeing condition 1 and 2 and why does refresh lose the whole session state in item 3 above?
@using Fluxor;
@using BlazorWizard.Store;
@using Blazorise;
@Inject IState state
@page "/wizarddemo"
@Inject IDispatcher dispatcher
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
<WizardStep Name="First" @bind-Enabled="@state.Value.States[0].Visible">
<div class="row">
<FirstStep></FirstStep>
</div>
</WizardStep>
<WizardStep Name="Second Step" @bind-Enabled="@state.Value.States[1].Visible">
<div class="row">
<p>Wow, you've reached the second step!</p>
</div>
</WizardStep>
<WizardStep Name="Final Step" @bind-Enabled="@state.Value.States[2].Visible">
<div class="row">
<p>The final step has been reached. Thank you \o/</p>
</div>
</WizardStep>
@code {
Wizard TheWizard { get; set; }
void OnSubmit()
{
if (state.Value.States[1].Visible == false)
{
dispatcher.Dispatch(new BlazorWizard.Store.Wizard.WizardAllOnAction());
System.Diagnostics.Debug.WriteLine("All On");
}
else
{
dispatcher.Dispatch(new BlazorWizard.Store.Wizard.WizardFirstOnAction());
System.Diagnostics.Debug.WriteLine("First ON");
}
StateHasChanged();
ShowStates();
}
protected override void OnInitialized()
{
// dispatcher.Dispatch(new BlazorWizard.Store.Wizard.WizardFirstOnAction());
// System.Diagnostics.Debug.WriteLine("First on Init");
//StateHasChanged();
base.OnInitialized();
}
protected override void OnParametersSet()
{
//state.StateChanged += (o, ws) =>
//{
// StateHasChanged();
//};
base.OnParametersSet();
}
void ShowStates()
{
System.Diagnostics.Debug.WriteLine("States");
foreach (var item in state.Value.States)
{
System.Diagnostics.Debug.WriteLine(item.Visible);
}
}
}
Just going through the tutorials, and have noticed what seems to be a mistake.
In the Tips section of Fluxor/Tutorials/02-Blazor/02A-StateActionsReducersTutorial, there are four methods that look like this...
[ReducerMethod]
public static SomeState(SomeState state, SomeAction action) => new SomeState();
Shouldn't these be more like this...
[ReducerMethod]
public static SomeState DoSomething(SomeState state, SomeAction action) => new SomeState();
The code as shown doesn't compile, unless I've missed something obvious (quite possible at this time of night!)
The same applies in the 01 tutorials section.
Hello.
Recently I wanted to try out using Fluxor.Blazor.Web v3.1.1 in a CSB project that I am currently developing. When I added builder.Services.AddFluxor(o => o.ScanAssemblies(typeof(Program.Assembly));
it turned out that the the application started about 2 minutes ...
When I added references to Fluxor.Blazor.Web.csproj / Fluxor.csproj to my project instead of nuget package and when I added simple loging, it turned out that e.g. in ReducerMethodsDiscovery.DiscoverReducerMethods
parameter allCandidateTypes
contained 2100 elements and the expression:
allCandidateTypes.SelectMany(t => t.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
returned 27760 elements.
Perhaps this is due to the fact that there are many components in the project, which additionally often are based on some abstract class with many methods.
When I added the logging of the results of the mentioned expression, it turned out that (if I'm not mistaken):
The execution time of the AddFluxor()
method was reduced to approx. 10 seconds, when e.g. in https://github.com/mrpmorris/Fluxor/blob/3.1.1/Source/Fluxor/DependencyInjection/DependencyScanner.cs to local IEnumerable variables definition I added .ToList()
at the end.
On a smaller scale, the problem can be reproduced, e.g. by cloning the repository https://github.com/SamProf/MatBlazor and adding the Fluxor in MatBlazor.Demo.ClientApp project:
builder.Services.AddFluxor (o => o.ScanAssemblies (typeof (MatBlazor.Demo.Components.BaseDocComponent) .Assembly));
Can assembly scanning be improved somehow?
Hi Peter,
If I enable options.UseReduxDevTools() I get the following error in the console.
I tried to debug without success. Am I missing something?
BTW, I find your API a lot more friendly than Redux.Net.
Thank you
Unhandled exception rendering component: Could not find '__FluxorDevTools__' in 'window'.
at System.Threading.Tasks.ValueTask`1[TResult].get_Result () <0x33ff8f8 + 0x00034> in <filename unknown>:0
at Fluxor.Blazor.Web.ReduxDevTools.ReduxDevToolsInterop.InitializeAsync (System.Collections.Generic.IDictionary`2[TKey,TValue] state) <0x2ee1208 + 0x000fc> in <filename unknown>:0
at Fluxor.Blazor.Web.ReduxDevTools.ReduxDevToolsMiddleware.InitializeAsync (Fluxor.IStore store) <0x2eca2f0 + 0x000e4> in <filename unknown>:0
at Fluxor.Store.InitializeMiddlewaresAsync () <0x2ec21e0 + 0x000f2> in <filename unknown>:0
at Fluxor.Store.ActivateStoreAsync () <0x2ec1648 + 0x000c4> in <filename unknown>:0
at Fluxor.Store.InitializeAsync () <0x2ec1000 + 0x000c4> in <filename unknown>:0
I encounter error when adding NuGet to VS2019 v.16.6.0 preview 3 as following (yellow warning in top of VS). Details give the following stacktrace:
StreamJsonRpc.RemoteInvocationException : Specified sequence has duplicate items
Parameter name: analyzerReferences[1]
at async StreamJsonRpc.JsonRpc.InvokeCoreAsyncTResult
at async Microsoft.CodeAnalysis.Remote.RemoteEndPoint.InvokeAsyncT
at Microsoft.VisualStudio.Telemetry.WindowsErrorReporting.WatsonReport.GetClrWatsonExceptionInfo(Exception exceptionObject)
---> (Remote Exception) {
"type": "System.ArgumentException",
"message": "Specified sequence has duplicate items
Parameter name: analyzerReferences[1]",
"stack": " at Microsoft.CodeAnalysis.PublicContract.ThrowArgumentItemNullOrDuplicateException[T](IEnumerable1 sequence, String argumentName) at Microsoft.CodeAnalysis.Solution.WithProjectAnalyzerReferences(ProjectId projectId, IEnumerable
1 analyzerReferences)
at Microsoft.CodeAnalysis.Project.WithAnalyzerReferences(IEnumerable1 analyzerReferencs) at Microsoft.CodeAnalysis.Remote.SolutionCreator.<UpdateProjectAsync>d__9.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) at Microsoft.CodeAnalysis.Remote.SolutionCreator.<UpdateProjectsAsync>d__7.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.CodeAnalysis.Remote.SolutionCreator.<UpdateProjectsAsync>d__6.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) at Microsoft.CodeAnalysis.Remote.SolutionCreator.<CreateSolutionAsync>d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at Microsoft.VisualStudio.Telemetry.WindowsErrorReporting.WatsonReport.GetClrWatsonExceptionInfo(Exception exceptionObject) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.CodeAnalysis.Remote.SolutionService.<CreateSolution_NoLockAsync>d__13.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.CodeAnalysis.Remote.SolutionService.<GetSolutionAsync>d__12.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.CodeAnalysis.Remote.CodeAnalysisService.<>c__DisplayClass17_0.<<GetSemanticClassificationsAsync>b__0>d.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.CodeAnalysis.Remote.ServiceBase.<RunServiceAsync>d__13
1.MoveNext()",
"code": -2147024809,
"inner": null
} <---
I made a simple search box that searches trough a list of some items. This code runs fairly fast (~1-2ms).
I added some console output to verify this, those outputs are shown in the chrome console instantly as I type.
And while the console instantly reflects what I type in the UI remains locked up and lags behind severely.
To make sure I removed all logic from my reducers and just returned the old state. This resulted in reducers that took less than a ms. However the result is the same.
Am I doing something wrong or is this a limit of the Fluxor framework?
private void OnSearchTextChanged(ChangeEventArgs e)
{
Dispatcher.Dispatch(new SearchInDossierListAction(e.Value.ToString()));
}
Hi,
I was able to get this up and running and everything works like charm, but passed some random time debugging my app, I'm getting an System.InvalidOperationException error and then it closes my debug session.
This is what I'm getting from the output:
An unhandled exception of type 'System.InvalidOperationException' occurred in Fluxor.dll
DisposableCallback with Id "StateSubscriber.Subscribe" was not disposed.
Do you have any idea what could I be doing wrong?
Thanks!
PS: awesome library!
I am using Fluxor.Blazor.Web 3.1.0 in my client-side Blazor application.
I created state, feature, action, effect and reducer to fetch data from API.
Everythink works fine, but I noticed some messages related with GC in browser console and performance problem - my api call takes 5 seconds. But in network tab in browser I can see that API call took 25ms an size is 60kB.
message in browser console:
L: GC_MAJOR_SWEEP: major size: 18896K in use: 29384K blazor.webassembly.js:1 L: GC_MAJOR: (LOS overflow) time 38.93ms, stw 38.94ms los size: 25520K in use: 17984K
so I tried to investigate the problem. In first glance I thougth that it is a problem with HttpClient, so I added Stopwatch to measure API call time.
Stopwatch stopWatch = new Stopwatch(); Console.WriteLine("fetch start " + url); stopWatch.Start(); var content = await _httpClient.GetStringAsync(url); Console.WriteLine("get in seconds: " + stopWatch.Elapsed.Seconds);
StopWatch shows 5 second per request and GC message was displayed in console.
So I tryied to do the same in empty application - without dependenceies, just single view and everythink was fine - API call took less than 0 seconds and there was no messages in console. In next steps I tryied to simplyfy my application to find the source of problem. After a few iterations of commenting and uncommenting code I relaized that problem is with State.
When State is created first time in reducer everythink is fine - data is displayed in UI very fast without problems. But when eg. user navigates to other page and after that goes back to first one, component dispathes Action again to fetch fresh data from API and this is fine. But in reducer new State object is created, old one is probably repleaced and this generates the performance problem and GC message in console. When I replaced "return line" in code below with "return new ActiveOrdersState(state.data)" each API call is fast and I do not have GC messages in console, but UI is not updated because State was not changed.
public class GetForecastDataSuccessActionReducer : Reducer<ActiveOrdersState, FetchActiveOrdersResultAction> { public override ActiveOrdersState Reduce(ActiveOrdersState state, FetchActiveOrdersResultAction action) { var data = action.Data; return new ActiveOrdersState(data); } }
I am not sure if it is an issue, but I have problem like that, I read documentation twice and looks like I did everything correctly. Do you know how to fix that?
Hi!
Great job with Fluxor!
I'm playing around with Blazor WASM 3.2.0 rev2 and found out something that might be an issue or my misunderstanding.
I've created couple of FluxorComponents. Everything works very well. But when I've placed one in MainLayout.razor its not refreshing itself after action dispatched form OnInitialized (Async too). I've moved it to Index.razor and inherited from FluxorComponent and it works again. Maybe base class for layouts could help?
Best regards
MR
Should it be possible to dispatch actions from the DevTools? I cannot get it to work, but is that expected?
I have followed the tutorial, so I have the IncrementCounterAction wired up, but nothing I have entered on the dispatcher tab has any effect when I click the dispatch button. I don't even get any error messages.
Is this a bug or just missing documentation?
I'm trying to write a component unit test. I've managed to inject Fluxor parts into my testhost but the events never seem to fire. Is there a sample unit test anywhere?
My feeling is that Fluxor is on track to become an important library in the world of modern .Net development. While interest in this repository seems relatively low (based on stars/watchers), I believe this will increase as related technologies (particularly Blazor) gain adoption, mainly due to a few key advantages Fluxor has over similar libraries and homemade state management patterns.
Knowing this, it seems that some kind of community -- even just a Gitter channel -- would be hugely beneficial as this progression plays out. Fluxor provides the developer with significant flexibility. I'd like to see how others are taking advantage of this, and be able to provide my own insight to other developers based on my experience with Fluxor.
Neither StackOverflow nor this GitHub "issues" page seem to be the most effective way to communicate with other developers using Fluxor. Please consider establishing some kind of online community to facilitate the growth of this important technology.
Message=DisposableCallback with Id "StateSubscriber.Subscribe" was not disposed.
It would be nice to be able to provide additional information explaining what the common causes of this error are. Perhaps add a link URL to an MD file on this repo.
Hi,
I've started to use Fluxor a few days ago. I'm developing a Blazor Webassembly app. My app calls a web API with a bearer token.
I've created an AuthState class, where the accessToken is stored. I dispatch a LoginAction, call my token endpoint in the Effect class, then dispatch a LoginResultAction, and in the AuthReducer class I create the new state with the token. It works fine, I can display the token in any components, so this part is great.
What I want to achieve, is to use this token in my DelegatingHandler, so when an Http request is sent, it sets the token from the AuthState. But whatever I do, the accessToken is always null in the DelegatingHandler.
Here is my code:
public class AuthenticationHandler : DelegatingHandler
{
private readonly IState<AuthState> _authState;
public AuthenticationHandler(IState<AuthState> authState)
{
_authState = authState;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var accessToken = _authState.Value.AccessToken;
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
return base.SendAsync(request, cancellationToken);
}
}
When I trying to get the AccessToken, it's value is always null. I tried registering the handler as Transient, it didn't help. (If I hardcode the token, it works fine.)
I'm new to blazor and fluxor as well, maybe I'm missing something, would be great if anyone could help me.
Is it possible to inject a dependency into the initial state?
Assuming the following Feature:
public class AppFeature : Feature<AppState>
{
private readonly IImportantDependency _importantDependency;
public override string GetName() => "App";
public AppFeature(IImportantDependency importantDependency)
{
_importantDependency = importantDependency;
}
protected override AppState GetInitialState()
{
return new AppState(_importantDependency);
}
}
Since base class Feature<TState>
calls the virtual method GetInitialState from its constructor, the GetInitialState method will get called before the derived class is fully initialized (before it's constructor is called) and thus before the IImportantDependency is resolved.
I could try to inject the IImportantDependency in : Effect<StoreInitializedAction>
and then Dispatch
and action with the IImportantDependency as a constructor parameter on the action, but the Task HandleAsync(StoreInitializedAction action, IDispatcher dispatcher)
gets called after the IImportantDependency is required.
Examples too simple and do not show real example of usage.
Please provide more complex State, at least 3-4 properties and more actions.
From examples does not clear follows how to use your library.
Hi,
I have 3 trees and 1 paged list, the trees branches all load on demand and using the state datasource causes them to refresh, I have used an event aggregator to publish a message to tell the handler to get the list from state and use the property in the code behind to bind to the tree. I can now add nodes to this without the refresh. If you were able to subscribe to a call back on the Effect it would be a little neater.
Ian.
RoutingMiddleware
dispatches a GoAction
whenever NavigationManager.LocationChanged' is triggered and the new URL doesn't match the URL in the state, An Effect will then trigger to call
NavigationManager.Navigate` if the state URL and current URL are different.
This allows us to ensure navigation occurs when dispatching GoAction, and that GoAction is dispatched when non-Fluxor code calls NavigationManager.Navigate
.
When using Microsoft MSAL authentication the quick changing of URLs can cause in endless redirect loop.
I need the effect to be executed synchronously, but as HandleAsync is called by Fluxor, I am not sure If I can make it so? Is there any way to ensure an action and its effect is finished before going to the nextline where the Dispatcher is used?
I was having some issues when disposing a Component that inherited from FluxorComponent until I realized I didn't call base.OnInitialized when overriding the method. This caused the subscription that is disposed later to be null triggering the exception. I'm creating this issue just to suggest that maybe it would be a good idea to add the remark that a call to base.OnInitialized is needed when using FluxorComponent and overriding OnInitialized.
Great work with the library.
I am currently having an issue when I try go to another route. The issue occurs weather I use an "a" tag or the navigation manager built into Blazor.
When I route I get the error :
[2020-08-18T12:48:27.447Z] Error: System.AggregateException: Exceptions were encountered while disposing components. (Object reference not set to an instance of an object.) (Object reference not set to an instance of an object.) (Object reference not set to an instance of an object.) (Object reference not set to an instance of an object.)
---> System.NullReferenceException: Object reference not set to an instance of an object.
at Fluxor.Blazor.Web.Components.FluxorComponent.Dispose(Boolean disposing)
at Fluxor.Blazor.Web.Components.FluxorComponent.Dispose()
at Microsoft.AspNetCore.Components.Rendering.ComponentState.TryDisposeInBatch(RenderBatchBuilder batchBuilder, Exception& exception)
--- End of inner exception stack trace ---
---> (Inner Exception #1) System.NullReferenceException: Object reference not set to an instance of an object.
at Fluxor.Blazor.Web.Components.FluxorComponent.Dispose(Boolean disposing)
at Fluxor.Blazor.Web.Components.FluxorComponent.Dispose()
at Microsoft.AspNetCore.Components.Rendering.ComponentState.TryDisposeInBatch(RenderBatchBuilder batchBuilder, Exception& exception)<---
---> (Inner Exception #2) System.NullReferenceException: Object reference not set to an instance of an object.
at Fluxor.Blazor.Web.Components.FluxorComponent.Dispose(Boolean disposing)
at Fluxor.Blazor.Web.Components.FluxorComponent.Dispose()
at Microsoft.AspNetCore.Components.Rendering.ComponentState.TryDisposeInBatch(RenderBatchBuilder batchBuilder, Exception& exception)<---
---> (Inner Exception #3) System.NullReferenceException: Object reference not set to an instance of an object.
at Fluxor.Blazor.Web.Components.FluxorComponent.Dispose(Boolean disposing)
at Fluxor.Blazor.Web.Components.FluxorComponent.Dispose()
at Microsoft.AspNetCore.Components.Rendering.ComponentState.TryDisposeInBatch(RenderBatchBuilder batchBuilder, Exception& exception)<---
if i try to manually override dispose I get a null refrence where base.Dispose(disposed);
is called:
(Inner Exception #2) System.NullReferenceException: Object reference not set to an instance of an object.
at Fluxor.Blazor.Web.Components.FluxorComponent.Dispose(Boolean disposing)
at EdenXRPlatform.Components.Reporting.Dashboard.Charts.Engagement.Dispose(Boolean disposed) in /home/dan/Workspace/Eden/XRPlatform/EdenXRPlatform/Components/Reporting/Dashboard/Charts/Engagement.razor.cs:line 32
at Fluxor.Blazor.Web.Components.FluxorComponent.Dispose()
at Microsoft.AspNetCore.Components.Rendering.ComponentState.TryDisposeInBatch(RenderBatchBuilder batchBuilder, Exception& exception)<---
Hi!
When i use complex object (instance of class A) as a state object:
public class A
{
public List<B> B_LIST { get; set; }
}
public class B
{
public List<C> C_LIST { get; set; }
}
public class C
{
public string Title { get; set; }
}
i always get value List C_LIST null. Is this by design?
When creating a DisposableAction with a parameter that will throw an exception, the ~DisposableAction finalizer will still execute, so only throw a "not disposed" exception in the finalizer if the object was successfully created.
Please add "Fluxor is a zero boilerplate Flux/Redux library for Microsoft DotNet." to the top of the GitHub page.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.