2017-12-16 20 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에서 할 일 항목을 제거하면 어떻게하면 감속기에서 상태를 업데이트 할 수 있습니까?

@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))); 
     }); 

그래서 질문은 내가 트리거해야 행동의 어떤 종류 : 나는 특급 들어

... 제거하기 위해 할 일의 ID로 내 구성 요소에서 todoActions.TodoRemove 조치를 파견 것 서버로부터의 성공적인 응답 후에 (단지 200이된다고 가정 해 봅시다)?

todoActions.TODO_LOAD을 다시 트리거합니다. 그것은 이전 상태와 목록을 병합 할 것이고 나는 todos double을 얻을 것이다. ...

그러나 우리는 상태를 변경하면 안된다. 그래서 새로운 todos가로드 될 때마다 상태를 새로 고쳐서는 안된다. . 권리?

또는 그냥 을 odoActions.TODO_REMOVE_SUCCESSED t 같은 새로운 액션을 만들고 상태 않고 서버에서 새로운 할 일 목록을 반환해야합니까 ... 같은 :

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

이 안티 패턴 있을까 ?

아마이 바보 같은 질문이지만, 내가 여기에 아이디어 ... 사전에

감사를하지 않습니다!

+0

나는 성공적으로 (그리고 실패한) 제거 작업을 수행하기 위해 올바른 길을 가고 있다고 말할 것입니다. – Alex

답변

0

나는 더 표준적이고 깨끗하며 쉬운 해결책을 줄 것이다. 또한 중복 문제를 해결하고 항상 상점을 올바르게 업데이트 할 것입니다.

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; 

이 그럼 당신은 왜 그렇게 배열과 ID로 선택 현재 할 일을 가지고 간단한 상태와 감속기를해야합니다 :

당신은 6 개 작업을해야합니다.

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; 
    } 
} 

그런 다음 당신이 3 개 효과해야합니다 : 우리는 우리의 효과에 모든 정상적인 사람을 처리하는 동안 우리는 여기에 모든 성공적인 작업을 처리하여 도도 구성 요소에서 마지막으로

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을 파견하여 ID를 연구하도록 방아쇠를 당기는 몇 가지 방법을 가지고 있다고 가정하고 있습니다. 동일한 방법으로 제거 할 수있는 다른 방법도 있습니다. 상점에서 수행 할 모든 수정 사항은 선택자를 통해 등록 된 구성 요소의 항목에 반영됩니다.

. . . 

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가 없음). 제 질문은 이것에 관한 것입니다. 할 일 목록을 삭제하기 위해 백엔드에 전화를 걸면 클라이언트에서 어떻게 업데이트합니까? – Mar

+0

당신이 아이템을 가져 오기위한 핸들링과 동일합니다. 'DELETE/todo/{id}'에게 문자열 id를 넘겨주는'deleteTodo'를 보냅니다. 당신의 효과에서'todoService'를 호출하십시오. 백엔드가 성공적으로 응답하면'deleteTodoSuccess'를 사용하여 상점에서 수행 할 작업을 간단히 제거 할 수 있습니다. 나는 당신의 백엔드가 무엇을 반환할지 모르지만 그렇게 될 것입니다. – AndreaM16