首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NgRx:如何在元还原器中使用服务?

NgRx:如何在元还原器中使用服务?
EN

Stack Overflow用户
提问于 2019-09-23 16:30:53
回答 1查看 4.9K关注 0票数 8

我使用自定义中间件(元减速器)在每次操作被删除时打印我的ngrx-store。我直接在app.module.ts中编写了中间件(还应该放在哪里呢?):

app.module.ts

代码语言:javascript
复制
// ...imports

// ...

// FIXME:
/**
 * console.log action and state(before action) each time an action is dipatched
 * @param reducer reducer
 */
export function debug(reducer: ActionReducer<AppState, Actions>): ActionReducer<AppState, Actions> {

    const logger = new LoggerService(); ////////////// ERROR \\\\\\\\\\\\\\

    return (state, action) => {

        logger.storeInfo('ACTION', action);
        logger.storeInfo('STATE', state);

        return reducer(state, action);
    };
}

export const metaReducers: MetaReducer<any>[] = [
    debug,
];

@NgModule({
    declarations: [AppComponent, LoggerServiceComponent],
    entryComponents: [],
    imports: [
        // ...
        StoreModule.forRoot(reducers, { metaReducers }),
        StoreRouterConnectingModule.forRoot(), // Connects RouterModule with StoreModule
    ],
    providers: [
       // ...
    ],
    bootstrap: [AppComponent],
})
export class AppModule {}

有一个错误,因为我的LoggerService被注入了一个存储(因为我希望我的所有日志都存储在ngx-store中。,但我也不能进入商店!。此外,我确信这不是访问服务的单例实例的好方法.

  • 我应该把我的元还原器放在一个类中,然后访问这个类的函数,但是我该如何做呢?
  • 是否有一种通用方法来访问任何服务,如SomeClass.getServiceInstance(type)
  • 你对如何做这件事有其他的想法吗?

编辑1-使用META_REDUCERS (第一次尝试失败)

app.module.ts

代码语言:javascript
复制
import { LoggerService } from './services/logger.service';
import { AppState, Actions } from './app.state';
import { StoreModule, MetaReducer, ActionReducer, META_REDUCERS } from '@ngrx/store';

/**
 * Injects a `LoggerService` inside a `MetaReducer`
 * @param logger a service that allows to log and store console.log() messages
 * @returns a `MetaReducer`
 */
function debugFactory(logger: LoggerService): MetaReducer<AppState> {
    return (reducer: ActionReducer<AppState, Actions>): ActionReducer<AppState, Actions> => {
        return (state, action) => {

           logger.storeInfo('ACTION', action);
           logger.storeInfo('STATE', state);

           return reducer(state, action);
        };
    };
}

/**
 * Injects a LoggerService inside the debug `MetaReducer` function
 * @param logger a service that allows to log and store console.log() messages
 * @returns A list of `MetaReducer`
 */
export function getMetaReducers(logger: LoggerService): MetaReducer<AppState>[] {
    return [debugFactory(logger)];
}

const reducers = {
    layout: layoutReducer,
    preferences: preferencesReducer,
    router: routerReducer,
    debug: debugReducer,
};

@NgModule({
    declarations: [AppComponent ],
    entryComponents: [],
    imports: [
        // ...
        StoreModule.forRoot(reducers),
        StoreRouterConnectingModule.forRoot(), // Connects RouterModule with StoreModule
    ],
    providers: [
        // ...
        {
            provide: META_REDUCERS,
            deps: [LoggerService],
            useFactory: getMetaReducers,
            multi: true,
        },
    ],
    bootstrap: [AppComponent],
})
export class AppModule {}

根据文档,这应该可以工作,但我在运行时有以下错误:

代码语言:javascript
复制
TypeError: "fn is not a function"

对应于此函数(在njrx存储库中):

代码语言:javascript
复制
/**
 * @param {...?} functions
 * @return {?}
 */
function compose(...functions) {
    return (/**
     * @param {?} arg
     * @return {?}
     */
    function (arg) {
        if (functions.length === 0) {
            return arg;
        }
        /** @type {?} */
        const last = functions[functions.length - 1];
        /** @type {?} */
        const rest = functions.slice(0, -1);
        return rest.reduceRight((/**
         * @param {?} composed
         * @param {?} fn
         * @return {?}
         */
        (composed, fn) => {
             return fn(composed) // <----- HERE
        }), last(arg));
    });
}

在调试器中,它显示函数数组(...functions)包含一些函数和一个数组,我怀疑这是getMetaReducers方法的结果。我怀疑这个例子可能是错误的,或者compose方法的实现有问题。

告诉我你在我的代码中看到了什么错误的东西。

编辑2-使用USER_PROVIDED_META_REDUCERS中提到的答案(第二次尝试失败)

已编辑的代码

代码语言:javascript
复制
// OLD

    providers: [
        // ...
        {
            provide: META_REDUCERS,
            deps: [LoggerService],
            useFactory: getMetaReducers,
            multi: true,
        },
    ],

// NEW

    providers: [
        // ...
        {
            provide: USER_PROVIDED_META_REDUCERS,
            deps: [LoggerService],
            useFactory: getMetaReducers,
        },
    ],

我的LoggerService似乎既没有正确传递,也没有初始化,因为我现在有了以下错误:

代码语言:javascript
复制
core.js:9110 ERROR TypeError: Cannot read property 'storeInfo' of undefined
    at http://localhost:8102/main.js:636:20
    at http://localhost:8102/vendor.js:109798:20
    at computeNextEntry (http://localhost:8102/vendor.js:108628:21)
    at recomputeStates (http://localhost:8102/vendor.js:108681:15)
    at http://localhost:8102/vendor.js:109029:26
    at ScanSubscriber.StoreDevtools.liftedAction$.pipe.Object.state [as accumulator] (http://localhost:8102/vendor.js:109081:38)
    at ScanSubscriber._tryNext (http://localhost:8102/vendor.js:120261:27)
    at ScanSubscriber._next (http://localhost:8102/vendor.js:120254:25)
    at ScanSubscriber.next (http://localhost:8102/vendor.js:114391:18)
    at WithLatestFromSubscriber._next (http://localhost:8102/vendor.js:122330:34)

如果我评论这些台词:

代码语言:javascript
复制
        logger.storeInfo('ACTION', action);
        logger.storeInfo('STATE', state);

不会抛出任何例外,但我的记录器也不能工作。

但是,至少商店本身配置正确,现在的问题只是LoggerService没有被正确地传递或初始化。我想我还是做错了什么

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-09-23 16:42:15

您应该尝试使用META_REDUCERS令牌作为记录在案注入元还原器。

(领导:从9月24日起,文档有点误导,工厂方法返回类型应该是MetaReducer而不是MetaReducer[]。检查代码库中的这个示例)

代码语言:javascript
复制
export debugFactory(logger: LoggerService): MetaReducer<AppState> {
 return (reducer: ActionReducer<AppState, Actions>): ActionReducer<AppState, Actions> => {
    return (state, action) => {

        logger.storeInfo('ACTION', action);
        logger.storeInfo('STATE', state);

        return reducer(state, action);
    };
  }
}

@NgModule({
  providers: [
    {
      provide: META_REDUCERS,
      deps: [LoggerService],
      useFactory: debugFactory,
      multi: true
    },
  ],
})
export class AppModule {}

更新:

自v8以来您可以使用ÙSER_PROVIDED_META_REDUCERS令牌:

代码语言:javascript
复制
export function getMetaReducers(logger: LoggerService): MetaReducer<AppState>[] {
 return [debugFactory(logger)];
}

providers: [
  {
     provide: USER_PROVIDED_META_REDUCERS,
     deps: [LoggerService],
     useFactory: getMetaReducers
  },
],

在这种情况下,提供的工厂方法必须返回MetaReducer[]。在这一功能中,“库”和“用户”提供的元还原器合并成一个集合。

您很可能会在存储和记录器服务之间碰到循环依赖关系,就像在创建存储期间,角的IOC容器将尝试在存储的创建完成之前实例化取决于存储的记录器服务。您可以通过“懒散地”访问记录器服务中的商店来解决这一问题,方法是将Injector注入其中并为该商店定义一个getter属性,如下所示:

代码语言:javascript
复制
private get() store{return this.injector.get(Store);}

ctor(private readonly injector: Injector){}
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58066622

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档