2017-12-16 21 views
0

サーバから新しいデータセットを受け取った後、リデューサから正しい状態を更新して返すのと混乱します。私は実際にサーバーの応答の後に何を返すか(状態を更新する方法)を理解していません。 は私の混乱についてより明確にできるようにするには:サーバコールの後の状態を更新しますか?

例えば:

// imports.. 

export function todoReducer(state = [], action) { 
    switch (action.type) { 
     // some cases... 

     case todoActions.TODO_LOADED: { 
      return [ 
       ...state, 
       { 
       ...action.payload 
       } 
      ]  
     } 

     // some more cases... 
     default: 
      return state; 
    } 
} 

と効果:藤堂アプリに私は減速を持っているでしょう

@Effect() todoList$: Observable<any> = this.action$ 
     .ofType(todoActions.TODO_LOAD) 
     .switchMap(() => { 
      return this.http 
      .get('/rest/todo-list') 
      .map((todos: Todos) => new todoActions.TodoLoaded(todos)) 
      .catch(err => Observable.of(new todoActions.TodoFailed(err))); 
     }); 

ときtodoActions.TODO_LOADがトリガーされたら、私は明らかにtodoリストを取得します。それまでは明らかです。

ただし、ユーザーがUIからToDoアイテムを削除した場合、私のレデューサーの状態を更新するにはどうすればよいですか?私はEXPについて

を削除して...するTODOのidを持つ私のコンポーネントからtodoActions.TodoRemoveアクションを派遣します:

@Effect() removeTodo$: Observable<any> = this.action$ 
     .ofType(todoActions.TODO_REMOVE) 
     .switchMap((action : todoActions.TodoRemove) => { 
      return this.http 
      .delete(`/rest/todo-list/${action.payload['todoId']}`) 
      .map(() => { 
       // What kind of action should I apply here? 
      }) 
      .catch(err => Observable.of(new todoActions.TodoFailed(err))); 
     }); 

そこで問題は、私がトリガーするアクションの種類ですサーバーからの応答が成功した後(私はわずか200になると思います)?

私がトリガーすればtodoActions.TODO_LOADもう一度。それは以前の状態とリストをマージし、私はtodosをダブルになるでしょう...

しかし、私たちは状態を変更するべきではありません...私は新しいtodosがロードされるたびに状態をリフレッシュすべきではありません.. 。 右?

または私はちょうどトンのような新しいアクションを作成しなければならないのは、をodoActions.TODO_REMOVE_SUCCESSEDと状態なしサーバから新しいToDoリストを返す...のような:

case todoActions.TODO_REMOVE_SUCCESSED: { 
    return [...action.payload ] 
} 

これはアンチパターンだろう?

多分これは愚かな質問ですが、私は...ここに事前に

おかげでアイデアを得ることはありません!

+0

私はあなたが成功した(そして失敗した)削除のアクションを実行する正しい道にいると思います。 – Alex

答えて

0

私はショットにもっと標準的でクリーンで簡単な解決策を与えるでしょう。また、重複の問題を解決し、常に店舗を適切に更新するつもりです。

あなたは6つのアクションが必要です。そして、あなたがドスの配列とidによって選択された現在のTODOを持っている簡単な状態で減速機を持っています

import { Action } from '@ngrx/store'; 

/* App Models */ 
import { Todo } from './todo.model'; 

export const TODO_GET = '[Todo] get todo'; 
export const TODO_GET_SUCCESS = '[Todo] get todo success'; 
export const TODO_DELETE = '[Todo] delete todo'; 
export const TODO_DELETE_SUCCESS = '[Todo] delete todo success'; 
export const TODO_GET_BY_ID = '[Todo] get todo by id'; 
export const TODO_GET_BY_ID_SUCCESS = '[Todo] get todo by id success'; 

// Gets Todos from APIs 
export class TodoGetAction implements Action { 
    readonly type = TODO_GET; 
} 

// Returns APIs fetched Todos 
export class TodoGetSuccessAction implements Action { 
    readonly type = TODO_GET_SUCCESS; 
    constructor(public payload: Todo[]) {} 
} 

// Deletes a Todo given its string id 
export class TodoDeleteAction implements Action { 
    readonly type = TODO_DELETE; 
    constructor(public payload: string) {} 
} 

// True -> Success, False -> Error 
export class TodoDeleteSuccessAction implements Action { 
    readonly type = TODO_DELETE_SUCCESS; 
    constructor(public payload: Todo[]) {} 
} 

// Takes the id of the todo 
export class TodoGetByIdAction implements Action { 
    readonly type = TODO_GET_BY_ID; 
    constructor(public payload: string) {} 
} 

// Returns todo by id 
export class TodoGetByIdSuccessAction implements Action { 
    readonly type = TODO_GET_BY_ID_SUccess; 
    constructor(public payload: Todo) {} 
} 

export type All = 
    | TodoGetAction 
    | TodoGetSuccessAction 
    | TodoDeleteAction 
    | TodoDeleteSuccessAction 
    | TodoGetByIdAction 
    | TodoGetByIdSuccessAction; 

を。そして、あなたは3つの効果があります

import { createFeatureSelector } from '@ngrx/store'; 
import { createSelector } from '@ngrx/store'; 

/* ngrx */ 
import * as TodoActions from './todo.actions'; 

/* App Models */ 
import { Todo } from './todo.model'; 

// Get all actions 
export type Action = TodoActions.All; 

export interface TodoState { 
    todos: Todo[]; 
    todoById: Todo; 
} 

// Initial state with empty todos array 
export const todoInitialState: TodoState = { 
    todos: [], 
    todoById: new Todo({}) 
} 

/* Selectors */ 
export const selectTodoState = createFeatureSelector< 
    TodoState 
>('todo'); 
// Select all Todos 
export const selectTodos = createSelector(
    selectTodoState, 
    (state: TodoState) => state.todos 
); 
export const selectTodoByID = createSelector(
    selectTodoState, 
    (state: TodoState) => state.todoById 
); 

export function todoReducer(
    state: TodoState = todoInitialState, 
    action: Action 
) { 
    switch (action.type) { 
    case TodoActions.TODO_GET_SUCCESS: 
     const oldTodos = state.todos; 
     // Add new todos to old ones 
     const newTodos = oldTodos.concat(action.payload); 
     // Cast to set to have only unique todos 
     const uniqueTodos = new Set(newTodos); 
     // Cast back to array to get an array out of the set 
     const finalTodos = Array.from(uniqueTodos); 
     return { 
     ...state, 
     todos: [...finalTodos] 
     } 
    case TodoActions.TODO_DELETE_SUCCESS: 
     return { 
     ...state, 
     todos: state.todos.filter(todo => return todo.id !== action.payload) 
     } 
    case TodoActions.TODO_GET_BY_ID_SUCCESS: 
     return { 
     ...state, 
     todoById: state.todos.filter(todo => return todo.id === action.payload)[0] 
     } 
    default: 
     return state; 
    } 
} 

::私達は私達が私達の影響ですべての通常のものを処理しながら、ここにすべて成功したアクションを処理

import { Injectable } from '@angular/core'; 
import { Actions, Effect } from '@ngrx/effects'; 
import { Store } from '@ngrx/store'; 

/** rxjs **/ 
import { mergeMap } from 'rxjs/operators/mergeMap'; 
import { catchError } from 'rxjs/operators/catchError'; 
import { map } from 'rxjs/operators/map'; 
import { of } from 'rxjs/observable/of'; 

/** ngrx **/ 
import * as TodoActions from './todo.actions'; 
import { AppState } from '../app-state.interface'; 

/** App Services **/ 
import { TodoService } from './province.service'; 

@Injectable() 
export class TodoEffects { 

    @Effect() 
    getTodos$ = this.actions$.ofType(TodoActions.TODO_GET).pipe(
    mergeMap(() => { 
     // I Imagine you can move your api call in such service 
     return this.todoService.getTodos().pipe(
     map((todos: Todo[]) => { 
      return new TodoActions.TodoGetSuccessAction(todos); 
     }), 
     catchError((error: Error) => { 
      return of(// Handle Error Here); 
     }) 
    ); 
    }) 
); 

    @Effect() 
    deleteTodo$ = this.actions$.ofType(TodoActions.TODO_DELETE).pipe(
    mergeMap((action) => { 
     return new TodoActions.TodoDeleteSuccessAction(action.payload); 
    }) 
); 

    @Effect() 
    getTodoByID$ = this.actions$.ofType(TodoActions.TODO_GET_BY_ID).pipe(
    mergeMap((action) => { 
     return new TodoActions.TodoGetByIdSuccessAction(action.payload); 
    }) 
); 

    constructor(
    private todoService: TodoService, 
    private actions$: Actions, 
    private store: Store<AppState> 
) {} 
} 

をそして最後に、あなたの藤堂のコンポーネントにあなたが派遣することができますし、店舗から新鮮な情報を得るために変更を購読する。もちろん、私はあなたが新しいGetTodoByIdを派遣して研究をトリガーするいくつかのメソッドを持っていると仮定しています。同じ方法で削除することができる他のメソッドもあります。ストアで行うすべての変更は、セレクタを介して購読されているコンポーネントのエントリに反映されます。

. . . 

todos$: Observable<Todo[]>; 
todoById$: Observable<Todo>; 

constructor(private store: Store<AppState>) { 
    this.todos$ = this.store.select(selectTodos); 
    this.todo$ = this.store.select(selectTodoById); 
} 

ngOnInit() { 
    this.store.dispatch(new TodoActions.TodoGetAction); 
} 
+0

あなたの例に感謝します!しかしながら; deleteTodo $ effectによって、クライアント上のtodoは削除されますが、データベースには削除されません(http reqはありません)。私の質問はすべてこれに関するものです。 ToDoを削除するためにバックエンドを呼び出すと、クライアント上でどのように更新されますか? – Mar

+0

あなたがアイテムを手に入れたときの扱いと同じです。 'DELETE/todo/{id}'に文字列idを渡す 'deleteTodo'を送ります。あなたのエフェクトで 'todoService'を呼び出します。バックエンドが成功した場合は、 'deleteTodoSuccess'を使ってストアからtodoを削除することができます。あなたのバックエンドが何を返すのか分かりませんが、そのようなものになります。 – AndreaM16

関連する問題