Giter Site home page Giter Site logo

Reducer Performance about redux.net HOT 7 OPEN

guillaumesalles avatar guillaumesalles commented on August 22, 2024 1
Reducer Performance

from redux.net.

Comments (7)

GuillaumeSalles avatar GuillaumeSalles commented on August 22, 2024 1

On a side note, C# 7 pattern matching would be great way to write clean reducers :
https://github.com/dotnet/roslyn/blob/features/patterns/docs/features/patterns.md

from redux.net.

hungnd1475 avatar hungnd1475 commented on August 22, 2024

One workaround for this is to use the Visitor Pattern. With this you only have to type cast one time and the Visitor will take care of the rest. Your example can be rewritten using the Visitor Pattern as follow.

First create an IVisitableAction inherited from IAction which can be visited by the Visitor.

public interface IVisitableAction : IAction
{
    LoginState Visit(LoginState prevState, ActionVisitor visitor);
}

Then with each action type you create a concrete class implementing IVisitableAction. Each class can contain their own additional information for the action.

public class LoginStarted : IVisitableAction
{
    public string Username { get; set; }
    public LoginState Visit(LoginState prevState, ActionVisitor visitor)
    {
        visitor.Visit(prevState, this);
    }
}

public class LoginSuccess : IVisitableAction
{
    public LoginState Visit(LoginState prevState, ActionVisitor visitor)
    {
        visitor.Visit(prevState, this);
    }
}

In the ActionVisitor class, add a Visit function for each concrete action class that perform the actual logic for it and return an appropriate state.

public class ActionVisitor 
{
    public LoginState Visit(LoginState prevState, LoginStarted action)
    {
        // here the Visitor can access action's properties
        DoLogin(action.Username);
        return new LoginState() { IsProcessingLogin = true };
    }

    public LoginState Visit(LoginState prevState, LoginSuccess action)
    {
        return new LoginState() { IsProcessingLogin = false };
    }
}

Now you can rewrite the reducer to utilize all this.

public static class Reducer
{
    static readonly ActionVisitor VISITOR = new ActionVisitor();
    public static LoginState Reduce(LoginState prevState, IAction action)
    {
        var visitableAction = action as IVisitableAction; // there is only one type casting here
        return visitableAction?.Visit(prevState, VISITOR) ?? prevState;
    }
}

from redux.net.

dinoc avatar dinoc commented on August 22, 2024

I'm not as familiar with the Visitor pattern, which probably makes this feel like it's harder to reason about what is going on. I can appreciate the use of this new pattern in this architecture but it probably won't be for everyone.

from redux.net.

GuillaumeSalles avatar GuillaumeSalles commented on August 22, 2024

Thanks @dinoc for the question.

First of all, it's important to note that clarity was my main focus when I made the reducers in the samples. In my experience, the type checking / casting has never caused a performance issue. Performance issues are often related to doing too much work on the UI thread or the shape of the state.

However, I can explain why I did not add an ActionType property on IAction and how to optimize your reducer.

I can see a major flaw to the enum ActionType. What will be the values of the enum ActionType if it was defined in the Redux.NET library? It's the responsibility of the consumer to define all the possible action types.

The is operator is slower than comparing enums but you will need to dispatch a LOT of different actions type to see the difference. (See this stackoverflow question for a benchmark http://stackoverflow.com/questions/686412/c-sharp-is-operator-performance)

The as operator is more efficient than the is operator + casting, but I choose not to use it for the reducer because it is a little more verbose.

The visitor pattern proposed by @hungnd1475 is a good solution. If you want to simplify it, you could use simple polymorphism.

public asbtract class ActionBase : IAction
{
    public abstract LoginState GetNewState(LoginState state);
} 

public static class Reducer
{
    public static LoginState Reduce(LoginState prevState, IAction action)
    {
        var actionBase = action as ActionBase; // there is only one type casting here
        return actionBase?.GetNewState(prevState) ?? prevState;
    }
}

The disadvantage of this solution comparing to the visitor pattern is that you associate the reducer business login directly to your action. If you use the visitor pattern or the polyformism solution, you lose some advantage of reducer composition given by the functional approach.

Hope it answer your questions !

from redux.net.

dinoc avatar dinoc commented on August 22, 2024

What about adding a simple GetClassName method on the ActionBase and comparing against those in the reducer? That would remove reducer logic from the action.

If you wanted to take that a step further too....creating a new Fody add in to weave a property in for the class name would be kind of cool too.

from redux.net.

dinoc avatar dinoc commented on August 22, 2024

Good news...there already is a fody add-in for this - https://github.com/NickStrupat/NameOf

from redux.net.

ahmad2smile avatar ahmad2smile commented on August 22, 2024

A bit late to the party But I think simple method overloading can clean up the if-else mess in reducers rather than Dynamic Polymorphism which would add more fuel to fire of redux boilerplate issue.

from redux.net.

Related Issues (20)

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.