Giter VIP home page Giter VIP logo

fluxor-persist's Introduction

Fluxor-persist

Fluxor-persist is a library to persist Fluxor states.

Introduction

Persisting states is a pretty common task .. in react I use redux-persist so this carries over some of the same ideas. Most often I use it to ensure a user doesn't lose their state on a page refresh or when leaving or returning to a site but this library has no blazor dependencies so it can be used anywhere.

Getting Started

Installation

You can download the latest release / pre-release NuGet packages from the official Fluxor-persist nuget pages.

Setup

The easiest way to get started is to look at the sample blazor app here(https://github.com/Tailslide/fluxor-persist)

To add Fluxor-persist to your existing blazor fluxor application you want to:

  • Add a NuGet package reference to Fluxor.Persist
  • Add .UsePersist() in Program.cs when building your existing Fluxor service with AddFluxor()
  • Make a class that implements IStringStateStorage to persist your state however you want. It just needs to be able to save and retrieve a string / string key value pair. You can alternative implement IObjectStateStorage if you need to persist using the state objects directly.
  • Add the following to your Program.cs to register both your state storage and the default persists json store handler:
builder.Services.AddScoped<IStringStateStorage, LocalStateStorage>();
builder.Services.AddScoped<IStoreHandler, JsonStoreHandler>();

Detecting Rehydrate

You can detect that state has been rehydrated from storage. I use this in my MainLayout which inherits from FluxorLayout. In OnInitialized after I intialize the middleware to detect state restore and force a refresh:

        this.SubscribeToAction<InitializePersistMiddlewareResultSuccessAction>(result =>
        {
            Console.WriteLine($"**** State rehydrated**");
            this.StateHasChanged();// we now have state, we can re-render to reflect binding changes
        });

Example State Storage Class for LocalStorage

using Blazored.LocalStorage;
using Fluxor.Persist.Storage;
using System.Threading.Tasks;

namespace Fluxor.Persist.Sample.Storage
{
    public class LocalStateStorage :IStringStateStorage
    {

        private ILocalStorageService LocalStorage { get; set; }

        public LocalStateStorage(ILocalStorageService localStorage)
        {
            LocalStorage = localStorage;
        }

        public async ValueTask<string> GetStateJsonAsync(string statename)
        {
            return await LocalStorage.GetItemAsStringAsync(statename);
        }

        public async ValueTask StoreStateJsonAsync(string statename, string json)
        {
            await LocalStorage.SetItemAsStringAsync(statename, json);
        }
    }
}

Advanced Usage - BlackList, WhiteList

You can blacklist or whitelist state names to indicate if they should be persisted. Use only a blacklist or a whitelist not both. Regardless of settings, the states @routing and PersistMiddleware are never persisted.

Examples:

.UsePersist(x => x.SetBlackList(new string[] { "mystate1", "mystate2" }))
.UsePersist(options => options.UseInclusionApproach())
.UsePersist(x => x.SetWhiteList(new string[] { "mystate1", "mystate2" }))

Advanced Usage - Persist, SkipPersist

Similarly, you can mark state classes to persit or not with [Persist] and [SkipPersist] attributes. States can be not persisted by default by initializing with .UsePersist(options => options.UseInclusionApproach())

Advanced Usage - Persist only some state properties

You can attribute your state records so that certain fields do not get serialized. To not persist a 'isloading' flag for example:

    public record LoginState (
        [property: JsonIgnore] bool IsLoading,
        int CounterValue
        ) 
    {        
        [JsonConstructor]
        public LoginState(int CounterValue) : this(false, CounterValue) { }
    }

BREAKING CHANGES IN 1.09

To convert from using persists pre-1.09 to 1.09+, you need the following changes:

This line can be removed from MainLayout and is no longer required:

Dispatcher.Dispatch(new InitializePersistMiddlewareAction() { StorageService = new LocalStateStorage(this.localStorage), RehydrateStatesFromStorage=true });

Your storage class that implements IStateStorage needs to change to use IStringStateStorage

The following two lines need to be added to Program.cs to register the default JSON handler and also your local storage class:

builder.Services.AddScoped<IStringStateStorage, LocalStateStorage>();
builder.Services.AddScoped<IStoreHandler, JsonStoreHandler>();

If you have a whitelist or a blacklist the method changed for setting them from:

.UsePersist(x => x.StateBlackList= "mystate1,mystate2")

to

.UsePersist(x => x.SetBlackList(new string[] { "mystate1", "mystate2" }))

BREAKING DEPENDENCY For Sample Project - Blazored.LocalStorage V4.0

Looks like there is a new version of Blazored.Localstorage that has an issue that affects the sample project: Blazored/LocalStorage#140

If you use Blazored.LocalStorage V4.1.1 + you will need to change your LocalStateStorage.cs class to use SetItemAsStringAsync instead of SetItemAsync. You will also need to clear localstorage as your states have been corrupted if you upgraded the nuget without making this change.

I updated the sample app to use this new method.

fluxor-persist's People

Contributors

240026763 avatar anddrzejb avatar davidnajar avatar lk-smit-ag avatar minhhieugma avatar tailslide avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

fluxor-persist's Issues

Potential for persisting with IndexedDB?

This is a great library btw and I've been using it extensively.

Probably a little too extensively ๐Ÿ˜…, because I'm having issues with the smaller local storage limits on mobile devices - or maybe the smaller limits on individual entries in local storage?

This is something I'm happy to have a go at when I have the time, but I wanted to get your quick take first:

Do you think there'd be any issues implementing this with persisting to IndexedDB instead of local storage?

I've been using your example implementation of IStringStateStorage but I assume it would just be a matter of implementing this to target IndexedDB? I've not used IndexedDB before and I'm not sure if it can take the sort of 'Bulk Insert' that might be necessary to be sufficiently performant.

But from this answer, it seems like it should be possible, at least back in 2018: Stack overflow answer

So it looks doable. But before I give it a go, have you any thoughts I should consider?

Many thanks

"double" serialization / deserialization issue

Hi,

I've got a strange issue.

The middleware was not able to rehydrate simple object
... The JSON value could not be converted to Sudoku.Store.Counter.StateCounter ...

I succeeded to overcome the issue by updating the method LocalStateStorage.GetStateJsonAsync

The problem seems coming from await LocalStorage.GetItemAsStringAsync(statename)

That I replaced successfully by await LocalStorage.GetItemAsync<string>(statename)

Sincerely,

Loosing state on navigating away

Hi, This is a really great library and i feel like it will solve my issue just need one affirmation. This is more of a question really. I am starting out on blazor and am using fluxor for my state management. Everything works fine but when i navigating away from a component i loose all the state, is that expected behavior when using fluxor? and i mean navigating away and not a page refresh. I believe in blazor on navigating away the component is usually destroyed and a new one created meaning all state will be lost. I figured Fluxor will help maintain the state but it seems thats not the case or there could be something i am missing?

regards

Fluxor persist not usable in non blazor projects

Is your feature request related to a problem? Please describe.

I'm currently sharing the same codebase between a blazor and Xamarin app. The MVVM library uses fluxor to do the state management, but as fluxor persist targets net6 this can't be added to the netstandard shared library

Describe the solution you'd like

Fluxor.Persist should target netstandard2.0, same as Fluxor itself

Describe alternatives you've considered

Of course when .NET maui is released (net6.0) this will not be an issue for mobile apps

Additional context

Prioritize State Loading

Is your feature request related to a problem? Please describe.
I'm using LocalStorage to persist my data and I've got an issue where I need a certain feature's state to be loaded before any others because it is used in the key of the others. Example: ZState needs to load before "LastUserSelectionState" because I'm storing things with keys like: "{authorized user}\{ZState.Value}\{LastUserSelection.Value}".

Currently, the features are loaded in alphabetical order by feature type full name. So ZState would load after LastUserSelection and therefore doesn't load LastUserSelection correctly.

Describe the solution you'd like
It would be great to have a feature priority level attribute. If I have a [FeatureState] class or record, I could have another attribute like [FeatureState, PriorityLoad(1)] where "1" denotes the priority level highest (1) to lowest (int max value).

Describe alternatives you've considered
The only other solution I can think of here is to name them alphabetically to prioritize them which is a naming convention snafu and a special rule that has to be remembered/documented.

Additional context
The issue code:

foreach (IFeature feature in Store.Features.Values.OrderBy(x => x.GetName()))

Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.

I am using Blazor Server and followed the instructions on setting this up e.g. this was added to main, where I essentially copy the sample LocalStateStorage class

builder.Services.AddBlazoredLocalStorage();
builder.Services.AddScoped<IStringStateStorage, LocalStateStorage>();
builder.Services.AddScoped<IStoreHandler, JsonStoreHandler>();

builder.Services.AddFluxor(config =>
{
    config
        .ScanAssemblies(typeof(Program).Assembly)
#if DEBUG
        .UseReduxDevTools(rdt =>
        {
            rdt.Name = "MY APP";
        })
#endif
        .UsePersist()
        ;
});

When I start my app, I see the error at the top of the page "Attempting to reconnect to the server: 1 of 8" the console has the following error "[2023-09-10T17:05:49.166Z] Error: Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.'.
log @ blazor.server.js:1
"
The page eventually loads and I can see my view, data has loaded, store is created in localstorage. I now click on a detail page for an item or navigate to another page etc. same error etc.

Am I missing something for the setup? Does this work with Blazor Server vs Blazor WASM? I am using "Fluxor Version="5.9.1" and Blazored.LocalStorage" Version="4.4.0"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.