Search code examples
angularrxjsngrxfluxngrx-store

Ngrx advantages over Observable Data Services architecture?


Both observable data service and Ngrx store provides a Store based solution for angular applications.

Ngrx uses the flux design pattern and requires a 3rd party library, in contrast of Observable data services which can be implemented with built in features of angular and rxjs and is in a way i guess is an angular design pattern by it self.

information regarding Observable Data Service architecture can be found here

I have read his article : Redux, RxJs and Ngrx Store - When to Use a Store And Why? to really understand what are the main problems that store based solution aim to solve , and the way i see it they both solve these main problems :

  • solves the Facebook counter problem which happened because of multiple actors changing the same data concurrently
  • the "extraneous props issue" when moving an input way down/up the component tree when only the bottom/top one really needs it (useless to all the components in the way - breaking SRP)

i see a cost when using Ngrx - the bundle size is bigger , plenty boiler plate code - for a simple feature need to change multiple files and impl an action , a reducer, if using ngrx side effects then also a loader action and error action.. the learning curve of understanding the concept and the way flux works is bigger then observable data services i guess..

one advantage however is the awesome dev tools it provides.

So the question is as the title states : Ngrx advantages over Observable Data Services architecture ?

a simple Todos observable data service store example :

 @Injectable()
    export class TodoStore {

    private _todos: BehaviorSubject<List<Todo>> = new BehaviorSubject(List([]));

    constructor(private todoBackendService: TodoBackendService) {
        this.loadInitialData();
    }

    get todos() {
        return asObservable(this._todos);
    }

    loadInitialData() {
        this.todoBackendService.getAllTodos()
            .subscribe(
                res => {
                    let todos = (<Object[]>res.json()).map((todo: any) =>
                        new Todo({id:todo.id, description:todo.description,completed: todo.completed}));

                    this._todos.next(List(todos));
                },
                err => console.log("Error retrieving Todos")
            );

    }

    addTodo(newTodo:Todo):Observable {

        let obs = this.todoBackendService.saveTodo(newTodo);

        obs.subscribe(
                res => {
                    this._todos.next(this._todos.getValue().push(newTodo));
                });

        return obs;
    }

    toggleTodo(toggled:Todo): Observable {
        let obs: Observable = this.todoBackendService.toggleTodo(toggled);

        obs.subscribe(
            res => {
                let todos = this._todos.getValue();
                let index = todos.findIndex((todo: Todo) => todo.id === toggled.id);
                let todo:Todo = todos.get(index);
                this._todos.next(todos.set(index, new Todo({id:toggled.id, description:toggled.description, completed:!toggled.completed}) ));
            }
        );

        return obs;
    }


    deleteTodo(deleted:Todo): Observable {
        let obs: Observable = this.todoBackendService.deleteTodo(deleted);

        obs.subscribe(
                res => {
                    let todos: List<Todo> = this._todos.getValue();
                    let index = todos.findIndex((todo) => todo.id === deleted.id);
                    this._todos.next(todos.delete(index));

                }
            );

        return obs;
    }


}

Solution

  • At a glance differences:

    • One single store for all state. Your example looks like you'd have one per kind of data: todo, events, contacts, etc. If you only have one kind of data then NgRx may be overkill.

    • Time travel debugging. Love this feature!

    You could google benefits of ngrx and see additional responses.