Perform Effortless CRUD Actions in Blazor DataGrid with Fluxor
Tags: blazor, datagrid, development, syncfusion
Published: 2024-02-23 10:20:27

---
title: Perform Effortless CRUD Actions in Blazor DataGrid with Fluxor
published: true
date: 2024-02-16 11:56:01 UTC
tags: blazor, datagrid, development, syncfusion
canonical_url: https://www.syncfusion.com/blogs/post/crud-blazor-datagrid-fluxor.aspx
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rgv9ppman11i2y8582ot.png
---
[Fluxor](https://fluxor.dev/ "Fluxor") is a useful tool for managing application states in a centralized manner, allowing for easier traceability of changes. It is a zero-boilerplate state management library for .NET that operates on the Flux and Redux principles. The goal of Fluxor is to simplify front-end development by providing a single-state store approach for multiple UIs, without the hassle of excessive boilerplate code. The Fluxor concepts are well-explained by Peter Morris and the Fluxor team in the following links:

- [Fluxor demos on GitHub](https://github.com/mrpmorris/Fluxor/blob/master/Docs/README.md "Fluxor demos on GitHub")
- [Fluxor reference documentation](https://fluxor.dev/ "Fluxor reference documentation")

In this blog, we’ll see how to integrate Fluxor with the Syncfusion [Blazor DataGrid](https://www.syncfusion.com/blazor-components/blazor-datagrid "Syncfusion Blazor DataGrid") and perform CRUD actions using state management principles.

**Note:** Before proceeding, refer to the [Blazor DataGrid documentation for getting started](https://blazor.syncfusion.com/documentation/datagrid/getting-started-with-web-app "Getting started with Blazor DataGrid") with the control.

## Adding Fluxor and initiating it in the project

Follow these steps to add Fluxor to your Blazor project:

1.First, install the [Fluxor.Blazor.Web](https://www.nuget.org/packages/Fluxor.Blazor.Web "Fluxor.Blazor.Web NuGet Package") NuGet package in the **.Client** project in your solution.
```
Install-Package Fluxor.Blazor.Web
```
2.Then, register Fluxor by adding the following code in the **Program.cs** file, just before the line that starts with **“await builder.Build()”:**.
```
builder.Services.AddFluxor(options => options.ScanAssemblies(typeof(Program).Assembly));
```
3.Define Fluxor using the following statement at the top of the **Program.cs** file.
```
using Fluxor;
```
4.To initialize Fluxor with the store when the app starts, add the following line to the top of the **App.razor** file.
```xml
<Fluxor.Blazor.Web.StoreInitializer />
```
5.Update the **wwwroot/index.html** file by adding the following code just above the <**/body**> tag.

```xml
<script src="_content/Fluxor.Blazor.Web/scripts/index.js"></script>
```

6.To enable the browser extension, install the [Fluxor.Blazor.Web.ReduxDevTools](https://www.nuget.org/packages/Fluxor.Blazor.Web.ReduxDevTools "Fluxor.Blazor.Web.ReduxDevTools NuGet Package") NuGet package.
```csharp
Install-Package Fluxor.Blazor.Web.ReduxDevTools
```
7.Finally, in the **Program.cs** file, add the following line.
```csharp
builder.Services.AddFluxor(options => { options.ScanAssemblies(typeof(Program).Assembly); options.UseReduxDevTools(); });
```

## Creating the store

Before integrating Fluxor with the Syncfusion Blazor DataGrid component, it’s necessary to create a Fluxor store. This is because CRUD operations are performed on state data, which is managed in a centralized manner. The store holds the entire app’s state, and all updates are performed through actions and reducers. The Fluxor store consists of the following folders:

- Actions
- Reducers
- States and Features
- Effects

### Creating the state

We next need to create a state. The state defines the data structure and serves as the centralized store for the entire app. In this case, we have created the **OrderState**.

Refer to the following code example.

```csharp
public record OrdersState: OrderLoadableState
{
   public List<Order> Orders { get; init; }
}
public class OrdersFeatureState : Feature<OrdersState>
{
   public override string GetName()
   {
        return nameof(OrdersState);
   }
   protected override OrdersState GetInitialState()
   {
       return new OrdersState
       {
           ...
       };
   }
}
```

The previous code example shows the addition of a **Feature** class that exposes the **OrderState** to **Fluxor**. This allows all updates to the state to be performed through actions and reducers. These updates are crucial in maintaining the integrity of the centralized state and ensuring that it accurately reflects the entire app’s state.

The Fluxor **Feature**<**T**>  class requires the implementation of two abstract methods:

- The first method returns the name that Fluxor will use for the feature.
- The second method sets up the initial state of the **OrderState**.

Next, we need an action to dispatch while performing CRUD actions in the Blazor DataGrid.

### Creating the action

Actions play an important role in Fluxor architecture. They are objects that describe changes to the state and are dispatched from components to be processed by reducers.

To perform CRUD operations with Fluxor, specific actions must be created for each operation. For instance, if you want to implement CRUD state management for a list of items, you should create actions for adding, updating, deleting, and retrieving the list of items.

Refer to the following code example to implement these actions.

```csharp
namespace FluxorSyncfusionGrid.Client.OrderStore.Actions
{
    public record SetOrderAction
    {
        public Order Order { get; set; }
    }
    public record UpdateOrderAction
    {
        public Order Order { get; set; }
    }
    public record ResetOrderAction
    { }
    public record AsyncLoadOrderAction 
    { 
        public int Id { get; set; }
    }
    public record AsyncUpdateOrderAction
    {
        public Order Order { get; set; }
    }
    public record AsyncAddOrderAction
    {
        public Order Order { get; set; }
    }
    public record AsyncDeleteOrderAction
    {
        public Order Order { get; set; }
    }
}
```

### Creating the reducers

As discussed in the Action section, we require a reducer method to handle the actions. Reducers play a crucial role in the Fluxor architecture by updating the state in response to dispatched actions. They are defined as functions that receive the current state and an action and then return a new state that reflects the changes described by the action.

For example, in the case of a CRUD state management for a list of items, the reducer would handle actions such as adding, updating, deleting, and retrieving the list of items, updating the state accordingly.

Refer to the following code example.

```csharp
public static class OrderReducer
{
     [ReducerMethod]
     public static OrderState OnSetOrder(OrderState state, SetOrderAction action)
     {
            return state with 
            {
               . . .
            };
     }
     [ReducerMethod]
     public static OrderState OnUpdateOrder(OrderState state, UpdateOrderAction action)
     {
         return state with 
         {
             . . .
         };
     }        
     . . .
}
```

We can see that the **UpdateOrder** reducer method receives a **currentState** as a parameter and returns a new state with the updated values.

We now have to create the **OrderService** to fetch the data from the API and corresponding CRUD action methods. Refer to the following code example.

```csharp
public class OrderService
{
    public async Task<List<Order>> GetOrders(int limit = 10)
    {
         List<Order> items;            
         items = await this.http.GetFromJsonAsync<List<Order>>($"{this.Url}posts?_limit={limit}");            
         return items;
    }
    public async Task<Order> AddOrder(Order Order)
    {
         HttpResponseMessage response = await this.http.PostAsJsonAsync($"{this.Url}posts", Order);
         Order savedOrder = await response.Content.ReadFromJsonAsync<Order>();
         return savedOrder;
    }
    public async Task<Order> UpdateOrder(Order Order)
    {
         HttpResponseMessage response = await this.http.PutAsJsonAsync($"{this.Url}posts/{Order.Id}", Order);
         Order savedOrder = await response.Content.ReadFromJsonAsync<Order>();
         return savedOrder;
    }
    public async Task<bool> DeleteOrder(Order Order)
    {
         await this.http.DeleteAsync($"{this.Url}posts/{Order.Id}");
         return true;
    }
}
```

### What are effects, and why are they needed?

Effects in Fluxor are utilized to separate the state update logic from the side effect logic. This separation makes the code easier to understand and maintain, as it clearly defines which portions of the code are responsible for updating the state and which are responsible for the side effects.

Effects are employed in Fluxor when a dispatched action requires access to resources outside the store. For instance, you could use an effect to retrieve data from a remote API in response to an action request. The effect would make the API call, and when the data is returned, it will dispatch another action to update the state with the obtained data. This separation of the logic of fetching data and updating the state enhances the code’s readability and maintainability.

In this example, we use the **Effects** method to fetch data from a remote service.

```csharp
public class OrdersEffects
{
    private readonly IState<OrdersState> State;
    private readonly OrderService OrderService;
    public OrdersEffects(IState<OrdersState> state, OrderService OrderService)
    {
        State = state;
        OrderService = OrderService;
    }
    [EffectMethod]
    public async Task AsyncLoadOrdersEffect(AsyncLoadOrdersAction action, IDispatcher dispatcher) 
    {
            
        List<Order> Orders = await this.OrderService.GetOrders(); //fetch the data from remote API 
        dispatcher.Dispatch(new SetOrdersAction { Orders = Orders }); //dispatch the action to set the Order data for maintaining the state
    }
}
```

## Integrating the Syncfusion Blazor DataGrid with Fluxor

Let’s integrate Fluxor with Syncfusion Blazor DataGrid to perform CRUD operations in it.

1.To access Fluxor resources, simply add the following code in the **Index.razor** file.
```
@inherits FluxorComponent
```
2.Add the **OrderState** and Fluxor **Dispatcher,** since we have to access and dispatch the actions.
```csharp
@inject IDispatcher Dispatcher
@inject Istate<OrdersState> OrdersState
```
  3.Next, we inject the **IActionSubscriber**. This will allow the **Order** class to subscribe to the action and be notified of changes in the state.
```csharp
@inject IActionSubscriber ActionSubscriber
```
4.Define the Syncfusion Blazor DataGrid in the same **Index.razor** file and directly bind the **Orders** collection from **OrdersState** to the grid using the **DataSource** property.
```xml
<SfGrid TValue="Order" ID="Grid" DataSource="@OrdersState.Value.Orders" Toolbar="Toolbaritems" AllowSorting="true" AllowFiltering="true" AllowPaging="true">
    . . .
    . . .
</SfGrid>
```
5.In the following code example, in the **OnInitialized** and **OnInitializedAsync** lifecycle functions, we subscribe the actions **Load** , **Update** , **Delete** , and **Add**.
```csharp
protected override void OnInitialized()
{
    base.OnInitialized();
    ActionSubscriber.SubscribeToAction<AsyncUpdateOrderAction>(this, (Action) =>
    {
         ChangeIdToChange();
    });
    ActionSubscriber.SubscribeToAction<AsyncLoadOrderAction>(this, (Action) =>
    {
         ChangeIdToChange(0);
    });
    ActionSubscriber.SubscribeToAction<ResetOrderAction>(this, (Action) =>
    {
         ChangeIdToChange(0);
    });
}


protected override async Task OnInitializedAsync()
{
    await base.OnInitializedAsync();
    if (!OrdersState.Value.Orders.Any())
    {
        await InvokeAsync(() => { Dispatcher.Dispatch(new AsyncLoadOrdersAction()); });
    }
}
```

So initially, the data will be fetched from the **Effects** method and then stored in the **State** since the **AsyncLoadOrderAction** was subscribed. Refer to the following code example.

```csharp
[EffectMethod]
public async Task AsyncLoadOrdersEffect(AsyncLoadOrdersAction action, IDispatcher dispatcher) 
{               
    List<Order> orders = await this.OrderService.GetOrders(); // Fetch the data
    dispatcher.Dispatch(new SetOrdersAction { Orders = orders }); // Dispatch the next action
}
```
6.Define the command column in DataGrid to perform the edit and delete operations using the Syncfusion [Blazor Dialog](https://blazor.syncfusion.com/documentation/dialog/getting-started "Getting started with Blazor Dialog component") component.
```xml
<SfDialog @ref="Dialog" Height="400px" Width="600px" @bind-Visible="@IsVisible" ShowCloseIcon="true" IsModal="true" >
    <DialogTemplates>
        <Header>Order Information</Header>
        <Content>
            <RenderOrderEditForm IsAdd="@IsAdd" EditFormButtonPressed="HandleFormButtonClick" Data="@RowData"/>           
        </Content>
    </DialogTemplates>
    <DialogPositionData X="@Xvalue" Y="@Yvalue"></DialogPositionData>
</SfDialog>
```
7.If we choose the **Save** button in the dialog component, then we have to dispatch the following action in it.
```csharp
if (Order.Id != 0)
{
    Dispatcher.Dispatch(new AsyncUpdateOrderAction { Order = Order });
}
```
The dispatch action will trigger the corresponding **AsyncUpdateOrderEffect** , where an API call is made to add the data to the state. Refer to the following code example for reference.
```csharp
[EffectMethod]
public async Task AsyncUpdateOrderEffect(AsyncUpdateOrderAction action, IDispatcher dispatcher) 
{             
    Order order = await this.OrderService.UpdateOrder(action.Order); // Call the OrderService method to update the data in the remote API            
    dispatcher.Dispatch(new UpdateOrderAction { Order = order });
    await Task.Delay(1);
    dispatcher.Dispatch(new UpdateSingleOrderOrdersAction { Order = order }); // Update internally by calling the corresponding action state
}
```

## Performing CRUD operations

Let’s perform CRUD operations in the Blazor DataGrid using Fluxor!

### Delete

If we delete an **Order** using the CommandColumn button, it will call the **OnDelete** method. In this method, we will dispatch the **AsyncDeleteOrderAction**.

```csharp
if (args.CommandColumn.Title.Equals("Delete"))
{
    OnDelete(Order);
}

public void OnDelete(Order item)
{
    Dispatcher.Dispatch(new AsyncDeleteOrderAction { Order = item });
}
```

The dispatch action will trigger the corresponding **AsyncDeleteOrderEffect** , where an API call is made to delete the data in the state.

```csharp
[EffectMethod]
public async Task AsyncDeleteOrderEffect(AsyncDeleteOrderAction action, IDispatcher dispatcher) 
{
    bool isDeleted = await this.OrderService.DeleteOrder(action.Order); // Call the API method to delete the Order item
    if (isDeleted)
    {
        dispatcher.Dispatch(new ResetOrderAction());
        await Task.Delay(1);
        dispatcher.Dispatch(new DeleteSingleOrderOrdersAction { Order = action.Order }); // Update internally by calling the corresponding action state
    }
}
```

### Add

Let’s add a new record to the DataGrid using the custom toolbar item. Refer to the following code example.

```csharp
<SfGrid TValue="Order" ID="Grid" DataSource="@OrdersState.Value.Orders" Toolbar="Toolbaritems" AllowSorting="true" AllowFiltering="true" AllowPaging="true">
    . . .
    . . .
</SfGrid>
@code{
    protected override void OnInitialized()
    {
        . . .
        . . .
        Toolbaritems.Add(new ItemModel() { Text = "New Order", TooltipText = "Add new"});
    }
}
```

The Dialog component will be displayed when we press the **New Order** button in the DataGrid toolbar. After entering the inputs, click **Save**.

```csharp
Dispatcher.Dispatch(new AsyncAddOrderAction { Order = Order });
```

The dispatch action will trigger the corresponding **AsyncAddOrderEffect** , where an API call is made to add the data to the state.

```csharp
[EffectMethod]
public async Task AsyncAddOrderEffect(AsyncAddOrderAction action, IDispatcher dispatcher) 
{ 
    Order order = await this.OrderService.AddOrder(action.Order);         
    order.Id = OrdersState.Value.Orders.Max(p => p.Id) + 1;          
    dispatcher.Dispatch(new UpdateOrderAction { Order = order });           
    await Task.Delay(1);
    dispatcher.Dispatch(new UpdateSingleOrderOrdersAction { Order = order });
}
```

### Update

The DataGrid UI will be automatically updated when CRUD actions are completed and stored in the state without requiring manual refresh or any other actions to reflect the changes in the grid.

After executing the previous code examples, the output will look like the following image.
<figure>

  <img src="https://www.syncfusion.com/blogs/wp-content/uploads/2024/02/Blazor-Data-Grid-Fluxor.gif" alt="Performing CRUD Actions in Blazor DataGrid with Fluxor" style="width:100%">

  <figcaption>Performing CRUD Actions in Blazor DataGrid with Fluxor</figcaption>

</figure>

## GitHub reference

Check out the complete example for this on [GitHub demos](https://github.com/SyncfusionExamples/blazor-datagrid-fluxor/ "Perform Effortless CRUD Actions in Blazor DataGrid with Fluxor GitHub demos").

## Conclusion

Thanks for reading! In this blog, we’ve learned how to integrate the Syncfusion [Blazor DataGrid](https://www.syncfusion.com/blazor-components/blazor-datagrid "Blazor DataGrid") with Fluxor and perform CRUD operations in it. Feel free to try out these steps and share your feedback in the comments section. For more details, refer to the [online demos](https://blazor.syncfusion.com/demos/datagrid/overview "Syncfusion Blazor online demos").

Syncfusion DataGrid is also available in the ASP.NET ([Core](https://www.syncfusion.com/aspnet-core-ui-controls/grid "Syncfusion ASP.NET Core Data Grid"), [MVC](https://www.syncfusion.com/aspnet-mvc-ui-controls/grid "Syncfusion ASP.NET MVC Data Grid")),  [Blazor](https://www.syncfusion.com/blazor-components/blazor-datagrid "Syncfusion Blazor Data Grid"), [Angular](https://www.syncfusion.com/angular-ui-components/angular-grid "Syncfusion Angular Data Grid"), [JavaScript](https://www.syncfusion.com/javascript-ui-controls/js-data-grid "Syncfusion JavaScript Data Grid"), [React](https://www.syncfusion.com/react-ui-components/react-data-grid "Syncfusion React Data Grid"), [Vue](https://www.syncfusion.com/vue-ui-components/vue-grid "Syncfusion Vue Data Grid"), [Xamarin](https://www.syncfusion.com/xamarin-ui-controls/xamarin-datagrid "Syncfusion Xamarin Data Grid"), [Flutter](https://www.syncfusion.com/flutter-widgets/flutter-datagrid "Syncfusion Flutter Data Grid"), [WinForms](https://www.syncfusion.com/winforms-ui-controls/datagrid "Syncfusion WinForms Data Grid"), [WPF](https://www.syncfusion.com/wpf-ui-controls/datagrid "Syncfusion WPF Data Grid"), [.NET MAUI](https://www.syncfusion.com/maui-controls/maui-datagrid "Syncfusion .NET MAUI Data Grid") and [WinUI](https://www.syncfusion.com/winui-controls/datagrid "Syncfusion WinUI Data Grid") platforms. Use this component wherever you need to build world-class apps!

The latest version of Essential Studio is available for existing customers from the [License and Downloads](https://www.syncfusion.com/account/downloads "Essential Studio License and Downloads page") page. If you are not yet a Syncfusion customer, you can try our 30-day [free trial](https://www.syncfusion.com/downloads "Get the free 30-day evaluation of Essential Studio products") to check out all the available features.

For questions, you can contact us through our [support forums](https://www.syncfusion.com/forums "Syncfusion Support Forums"), [support portal](https://support.syncfusion.com/ "Syncfusion Support Portal"), or [feedback portal](https://www.syncfusion.com/feedback/ "Syncfusion Feedback Portal"). We are always happy to assist you!

## Related blogs

  - [Mastering State Maintenance in Blazor Tabs](https://www.syncfusion.com/blogs/post/state-maintenance-blazor-tabs.aspx "Blog: Mastering State Maintenance in Blazor Tabs")
  - [Enhancing the Blazor File Manager Performance with Virtualization](https://www.syncfusion.com/blogs/post/blazor-file-manager-virtualization.aspx "Blog: Enhancing the Blazor File Manager Performance with Virtualization")
  - [Transforming a Blazor WebAssembly (WASM) App into a Progressive Web App](https://www.syncfusion.com/blogs/post/transform-blazor-wasm-to-pwa.aspx "Blog: Transforming a Blazor WebAssembly (WASM) App into a Progressive Web App")
  - [Explore the Possibilities of the Blazor Playground App](https://www.syncfusion.com/blogs/post/syncfusion-blazor-playground-app.aspx "Blog: Explore the Possibilities of the Blazor Playground App")