angular - 如何在 ngrx/Store reducer 中使用其他 Angular2 服务?

标签 angular dependency-injection redux ngrx

ngrx/Store 和 reducer 都是新的。基本上,我有这个 reducer :

import {StoreData, INITIAL_STORE_DATA} from "../store-data";
import {Action} from "@ngrx/store";
import {
  USER_THREADS_LOADED_ACTION, UserThreadsLoadedAction, SEND_NEW_MESSAGE_ACTION,
  SendNewMessageAction
} from "../actions";
import * as _ from "lodash";
import {Message} from "../../shared-vh/model/message";
import {ThreadsService} from "../../shared-vh/services/threads.service";

export function storeData(state: StoreData = INITIAL_STORE_DATA, action: Action): StoreData {


  switch (action.type) {

    case SEND_NEW_MESSAGE_ACTION:
      return handleSendNewMessageAction(state, action);

    default:
      return state
  }
}

function handleSendNewMessageAction(state:StoreData, action:SendNewMessageAction): StoreData {

  const newStoreData = _.cloneDeep(state);

  const currentThread = newStoreData.threads[action.payload.threadId];

  const newMessage: Message = {
    text: action.payload.text,
    threadId: action.payload.threadId,
    timestamp: new Date().getTime(),
    participantId: action.payload.participantId,
    id: [need a function from this service: ThreadsService]
  }

  currentThread.messageIds.push(newMessage.id);

  newStoreData.messages[newMessage.id] = newMessage;

  return newStoreData;
}

问题出在 reducer 函数中,我不知道如何注入(inject)我在不同文件中创建的可注入(inject)服务并使用其中的函数。 id 部分 - 我需要使用 this.threadService.generateID() 之类的函数生成一个 firebase 推送 ID ...

但由于这是一个函数,我没有使用 DI 的构造函数,我也不知道如何在 threadService 中获取函数!

最佳答案

没有将服务注入(inject) reducer 的机制。 reducer 应该是纯函数。

相反,您应该使用 ngrx/effects - 这是实现 Action 副作用的机制。 Effects 监听特定的 Action ,执行一些副作用,然后(可选)发出进一步的 Action 。

通常,您会将您的操作分为三部分:请求;成功响应;和错误响应。例如,您可以使用:

SEND_NEW_MESSAGE_REQ_ACTION
SEND_NEW_MESSAGE_RES_ACTION
SEND_NEW_MESSAGE_ERR_ACTION

你的效果看起来像这样:

import { Injectable } from "@angular/core";
import { Actions, Effect, toPayload } from "@ngrx/effects";
import { Action } from "@ngrx/store";
import { Observable } from "rxjs/Observable";
import "rxjs/add/operator/map";

@Injectable()
export class ThreadEffects {

  constructor(
    private actions: Actions,
    private service: ThreadsService
  ) {}

  @Effect()
  sendNewMessage(): Observable<Action> {

    return this.actions
      .ofType(SEND_NEW_MESSAGE_REQ_ACTION)
      .map(toPayload)
      .map(payload => {
        try {
          return {
              type: SEND_NEW_MESSAGE_RES_ACTION,
              payload: {
                  id: service.someFunction(),
                  // ...
              }
          };
        } catch (error) {
          return {
              type: SEND_NEW_MESSAGE_ERR_ACTION
              payload: {
                error: error.toString(),
                // ...
              }
          };
        }
      });
  }
}

你的 reducer 不是与服务交互,而是一个只需要处理 SEND_NEW_MESSAGE_RES_ACTION 的纯函数。和 SEND_NEW_MESSAGE_ERR_ACTION对成功或错误有效载荷做一些适当的事情。

效果是基于可观察的,因此合并同步、基于 promise 或基于可观察的服务是直截了当的。

有一些effectsngrx/example-app .

关于您在评论中的查询:

.map(toPayload)只是为了方便。 toPayload是一个 ngrx存在的函数,因此它可以传递给 .map提取操作的 payload ,仅此而已。

调用基于可观察的服务非常简单。通常,你会做这样的事情:

import { Observable } from "rxjs/Observable";
import "rxjs/add/observable/of";
import "rxjs/add/operator/catch";
import "rxjs/add/operator/map";
import "rxjs/add/operator/switchMap";

@Effect()
sendNewMessage(): Observable<Action> {

  return this.actions
    .ofType(SEND_NEW_MESSAGE_REQ_ACTION)
    .map(toPayload)
    .switchMap(payload => service.someFunctionReturningObservable(payload)
      .map(result => {
        type: SEND_NEW_MESSAGE_RES_ACTION,
        payload: {
          id: result.id,
          // ...
        }
      })
      .catch(error => Observable.of({
        type: SEND_NEW_MESSAGE_ERR_ACTION
        payload: {
          error: error.toString(),
          // ...
        }
      }))
    );
}

此外,效果可以声明为返回 Observable<Action> 的函数或作为 Observable<Action> 类型的属性.如果您正在查看其他示例,您可能会遇到这两种形式。

关于angular - 如何在 ngrx/Store reducer 中使用其他 Angular2 服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41796291/

相关文章:

angular - 如何卸载/升级 Angular CLI?

angular - 忽略构建的 Angular 模板错误

dependency-injection - 关于工厂模式和依赖注入(inject)的得墨忒耳定律

c# - 在 .net 核心中使用构造函数参数进行依赖注入(inject)

javascript - 如何在不中断异步流程的情况下在 redux 中自动刷新 JWT?

javascript - 为什么使用当前状态作为参数时this.state中的()

angular - 使用 tick 和 fakeAsync 对 Observable 进行单元测试 Angular 组件

java - Spring 请求范围的 bean - 所有字段为空/空

django - 获取 Django POST 请求的 API

angular - 通过更改数据绑定(bind)对象的属性触发 OnChanges