Вопрос или проблема
Когда я включаю provideEffects(ConfigEffects)
в main/ts -> app.config.ts
, я получаю следующую ошибку
TypeError: this.actions$ не определен
ConfigEffects config.effects.ts:23
createEffect Angular
ConfigEffects config.effects.ts:20
_ConfigEffects config.effects.ts:13
ConfigEffects_Factory main.js:70
Angular 18
<anonymous> main.ts:5
Почему this.actions$ не внедряется? Я пропускаю какие-то конфигурации?
Буду благодарен за любую помощь.
Пожалуйста, дайте знать, если нужны дополнительные детали.
У меня есть конфигурация в public/config/config.json
следующего вида
{
"auth0": {
"domain": "xxxx.us.auth0.com",
"clientId": "xxxxx",
"redirectUri": "http://localhost:4200",
"logoutRedirectUri": "http://localhost:4200",
"audience": "https://xxxxx/"
}
}
Мой main.ts -> app.config.ts
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
provideHttpClient(),
provideStore({ config: configReducer }),
provideEffects(ConfigEffects)
]
};
app.component.ts
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, RouterOutlet],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent {
config$: Observable<any>;
constructor(private store: Store) {
this.config$ = this.store.select(selectConfig);
}
ngOnInit(): void {
this.store.dispatch(loadConfig());
}
}
config.effect.ts
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { ConfigService } from './config.service';
import * as ConfigActions from './config.actions';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { of } from 'rxjs';
@Injectable()
export class ConfigEffects {
constructor(
private actions$: Actions,
private configService: ConfigService
) {
console.log('Actions:', this.actions$);
console.log('ConfigService:', this.configService);
}
loadConfig$ = createEffect(() => {
console.log('loadConfig...');
return this.actions$.pipe(
ofType(ConfigActions.loadConfig),
mergeMap(() =>
this.configService.loadConfig().pipe(
map((config) => ConfigActions.loadConfigSuccess({ config })),
catchError((error) => of(ConfigActions.loadConfigFailure({ error })))
)
)
)
});
}
В предыдущем коде loadConfig$
инициализируется до того, как actions$
получит значение, поэтому вы можете столкнуться с этой проблемой.
Один из способов решить это – установить "useDefineForClassFields": false
в tsconfig.json
, если вы используете ES2022
.
Вы также можете попробовать inject
перед определением loadConfig$
, чтобы actions$
всегда было доступно.
import { Injectable, inject } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { ConfigService } from './config.service';
import * as ConfigActions from './config.actions';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { of } from 'rxjs';
@Injectable()
export class ConfigEffects {
actions$: Actions = inject(Actions);
loadConfig$ = createEffect(() => {
console.log('loadConfig...');
return this.actions$.pipe(
ofType(ConfigActions.loadConfig),
mergeMap(() =>
this.configService.loadConfig().pipe(
map((config) => ConfigActions.loadConfigSuccess({ config })),
catchError((error) => of(ConfigActions.loadConfigFailure({ error })))
)
)
);
});
constructor(private configService: ConfigService) {
console.log('Actions:', this.actions$);
console.log('ConfigService:', this.configService);
}
}
Связанная проблема на GitHub 1
Связанная проблема на GitHub с обходными путями
Ответ или решение
Чтобы загрузить конфигурацию при инициализации приложения Angular и избежать ошибки, связанной с отсутствием зависимости this.actions$
, вы можете использовать несколько подходов. Рассмотрим их.
Проблема
Ошибка TypeError: this.actions$ is undefined
, как правило, возникает из-за того, что loadConfig$
инициализируется до того, как actions$
получает значение. Это может происходить, если вы используете ES2022 и настройки компиляции TypeScript по умолчанию.
Решение 1: Изменение tsconfig.json
Одним из способов решения этой проблемы является добавление "useDefineForClassFields": false
в ваш tsconfig.json
. Это изменение переключает поведение объявления свойств классов и может помочь избежать этой проблемы.
{
"compilerOptions": {
"useDefineForClassFields": false,
// другие настройки...
}
}
Решение 2: Использование inject
Вместо того чтобы инициализировать actions$
в конструкторе, вы можете воспользоваться функцией inject
для его получения. Это гарантирует, что actions$
всегда будет доступен.
Вот переписанный код вашего config.effects.ts
:
import { Injectable, inject } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { ConfigService } from './config.service';
import * as ConfigActions from './config.actions';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { of } from 'rxjs';
@Injectable()
export class ConfigEffects {
actions$ = inject(Actions); // Используем 'inject' для получения Actions
loadConfig$ = createEffect(() => {
console.log('loadConfig...');
return this.actions$.pipe(
ofType(ConfigActions.loadConfig),
mergeMap(() =>
this.configService.loadConfig().pipe(
map((config) => ConfigActions.loadConfigSuccess({ config })),
catchError((error) => of(ConfigActions.loadConfigFailure({ error })))
)
)
);
});
constructor(private configService: ConfigService) {
console.log('Actions:', this.actions$);
console.log('ConfigService:', this.configService);
}
}
Общее решение
В вашем app.config.ts
вам стоит убедиться, что все необходимые провайдеры и зависимости подключены корректно:
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
provideHttpClient(),
provideStore({ config: configReducer }),
provideEffects(ConfigEffects) // Убедитесь, что этот эффект правильно регистрируется
]
};
Завершение
После внесения указанных изменений, ваша проблема с this.actions$
должна быть решена, и вы сможете корректно загружать конфигурацию при инициализации приложения. Если вам понадобится дополнительная помощь или возникнут другие вопросы, не стесняйтесь обращаться.