react-spa-template/docs/flux-vs-mvvm.md
2025-04-19 19:24:27 +02:00

2.7 KiB

Flux vs. MVVM Architecture

Decision Matrix: Flux vs. MVVM

Criterion Plain Effector (Flux) MVVM Layer on Top
Boilerplate Low Higher
React Ecosystem Fit Native Non-idiomatic
Two-way Binding Risk None Possible
Testability High (domain files are pure) High but more layers
Refactor Complexity Lower Higher

Why We Chose Flux with Effector

For our React SPA, we've adopted an "Effector-based Flux architecture" for the following reasons:

  1. Better React Integration: Flux's unidirectional data flow aligns perfectly with React's rendering model.

  2. Simplicity: Fewer abstractions and less boilerplate compared to MVVM.

  3. Predictability: One-way data flow makes it easier to trace how state changes propagate through the application.

  4. Testability: Pure functions in model.ts are easy to test without complex mocking.

  5. TypeScript Friendly: Effector has excellent TypeScript support, providing type safety throughout the application.

Flux Architecture Flow

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Actions   │────>│    Store    │────>│    View     │
│ (Events)    │     │ (State)     │     │ (React)     │
└─────────────┘     └─────────────┘     └─────────────┘
       ▲                                       │
       │                                       │
       └───────────────────────────────────────┘
                   User Interaction

Effector Implementation

Effector provides three main primitives that map to Flux concepts:

  1. Events (Actions): Trigger state changes

    export const setProductName = createEvent<string>();
    
  2. Stores (State): Hold application state

    export const $product = createStore(initialState)
      .on(setProductName, (state, name) => ({ ...state, name }));
    
  3. Effects (Async Actions): Handle side effects

    export const fetchProductFx = createEffect(async (id: string) => {
      return await api.getProduct(id);
    });
    

Conclusion

While MVVM is a valid architecture pattern, Flux with Effector provides a more natural fit for React applications, with less boilerplate and better alignment with React's unidirectional data flow model. This approach keeps our codebase clean, testable, and maintainable.