Actions/state to load data from backend

匆匆过客 提交于 2019-12-03 18:40:39

问题


I've just started experimenting with ngxs but from my reading so far I'm not 100% clear on where I should be calling back to my API to persist and read data (all examples I've seen are either not doing it, or using some mock).

E.g. I've created a state where I maintain a list of items. When I want to add an item, I dispatch the 'AddItem` action to the store, where I add that new item to the state. This all works ok - the question is where is the appropriate place to plug in the call that POSTs the item to the server?

Should I call the API in my action implementation i.e. just before I update the store's item list.

Or should I call the API in my Angular component (via a service), then dispatch the 'Add Item' action when I received a response?

I'm quite new to this area, so any guidance or pros/cons of these approaches would be great.


回答1:


The best place is in your action handler.

import { HttpClient } from '@angular/common/http';
import { State, Action, StateContext } from '@ngxs/store';
import { tap, catchError } from 'rxjs/operators';

//
// todo-list.actions.ts
//
export class AddTodo {
  static readonly type = '[TodoList] AddTodo';
  constructor(public todo: Todo) {}
}


//
// todo-list.state.ts
//
export interface Todo {
  id: string;
  name: string;
  complete: boolean;
}
​
export interface TodoListModel {
  todolist: Todo[];
}
​
@State<TodoListModel>({
  name: 'todolist',
  defaults: {
    todolist: []
  }
})
export class TodoListState {

  constructor(private http: HttpClient) {}
​
  @Action(AddTodo)
  feedAnimals(ctx: StateContext<TodoListModel>, action: AddTodo) {

    // ngxs will subscribe to the post observable for you if you return it from the action
    return this.http.post('/api/todo-list').pipe(

      // we use a tap here, since mutating the state is a side effect
      tap(newTodo) => {
        const state = ctx.getState();
        ctx.setState({
          ...state,
          todolist: [ ...state.todolist, newTodo ]
        });
      }),
      // if the post goes sideways we need to handle it
      catchError(error => window.alert('could not add todo')),
    );
  }
}

In the example above we don't have a explicit action for the return of the api, we mutate the state based on the AddTodo actions response.

If you want you can split it into three actions to be more explicit,

AddTodo, AddTodoComplete and AddTodoFailure

In which case you will need to dispatch new events from the http post.




回答2:


If you want to separate the effect from the store you could define a base state class:

@State<Customer>( {
    name: 'customer'
})
export class CustomerState {
    constructor() { }

    @Action(ChangeCustomerSuccess)
    changeCustomerSuccess({ getState, setState }: StateContext<Customer>, { payload }: ChangeCustomerSuccess ) {
        const state = getState();
       // Set the new state. No service logic here.
       setState( {
           ...state,
           firstname: payload.firstname, lastname: lastname.nachname
       });
    }
}

Then you would derive from that state and put your service logic in the derived class:

@State<Customer>({
    name: 'customer'
})
export class CustomerServiceState extends CustomerState {

    constructor(private customerService: CustomerService, private store: Store) {
        super();
    }

    @Action(ChangeCustomerAction)
    changeCustomerService({ getState, setState }: StateContext<Customer>, { payload }: ChangeCustomerAction) {

        // This action does not need to change the state, but it can, e.g. to set the loading flag.
        // It executes the (backend) effect and sends success / error to the store.

        this.store.dispatch( new ChangeCustomerSuccess( payload ));
    }
}

I have not seen this approach in any of the NGXS examples I looked through, but I was looking for a way to separate those two concerns - UI and backend.



来源:https://stackoverflow.com/questions/49974877/ngxs-actions-state-to-load-data-from-backend

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!