我是ngrx和Redux风格架构的新手,我在理解如何链接动作/效果方面遇到了问题.一个例子是实现基本功能,例如在用户登录后采取行动.我的核心斗争是在用户登录后要采取的行动将根据应用程序的当前状态而变化 - 用户可能在任何地方在提交登录提示/页面时在应用程序中.
我见过的任何一些例子,一旦用户登录就会发生硬编码效果.在我的场景中,这不符合上述说法,我并不总是希望同样的动作发生.
以下是包含登录组件的主页的一些示例代码.在这种情况下,我希望用户在登录后重定向到"/ buy".
@Component(..)
export class HomePageComponent {
constructor(private store: Store<any>) {
}
public onLoginSubmitted(username, password) {
this.store.dispatch(new loginActions.Login({username, password}));
// once this has happened successfully navigate to /buy
}
}
Run Code Online (Sandbox Code Playgroud)
示例效果
@Injectable()
export class LoginEffects {
......
@Effect()
login$ = this.actions$
.ofType(loginActions.ActionTypes.LOGIN)
.switchMap((data) => {
return this.loginService.login(data.payload)
.map(() => new loginActions.LoginSuccess({loggedIn: true, isLoggingIn: false}))
.catch((error) => {
return of(new loginActions.LoginError({loggedIn: false, isLoggingIn: false}));
});
});
......
}
Run Code Online (Sandbox Code Playgroud)
关于如何解决这个问题,我有几点想法 - 但他们都不是正确的.这些包括
任何人都可以指出我应该如何解决这个问题的正确途径/现有例子吗?
我刚刚开始学习@ ngrx/store和@ ngrx.effects,并在我的Angular/Ionic应用程序中创建了我的第一个效果.它第一次运行正常但如果我再次将事件发送到商店(即再次单击按钮),则没有任何反应(没有进行网络调用,控制台日志中没有任何内容).有什么明显的东西我做错了吗?这是效果:
@Effect() event_response$ = this.action$
.ofType(SEND_EVENT_RESPONSE_ACTION)
.map(toPayload)
.switchMap((payload) => this.myService.eventResponse(payload.eventId,payload.response))
.map(data => new SentEventResponseAction(data))
.catch((error) => Observable.of(new ErrorOccurredAction(error)));
Run Code Online (Sandbox Code Playgroud)
谢谢
我从一个组件发出一个动作
this.store.dispatch({type : STORE_TEAMCREST , payload : team.crestURI});
Run Code Online (Sandbox Code Playgroud)
在另一个组件中,我从商店中选择使用
this.store.select(state => state.table.teamCrest).subscribe(data => this.teamCrest = data);
Run Code Online (Sandbox Code Playgroud)
如果我的应用程序按顺序向后或向前进行,这样可以正常工作,但是一旦我执行浏览器刷新状态,就会失去它的值,如何保留它的值,以便它可以在浏览器刷新时运行.
我有一组静态数据,一组国家,用于某些组件.这些数据加载到ngOnInit()这些组件中,但我想加载它们只是在我第一次请求数据时(存储是空的).每次我加载组件时我只想使用商店中的数据而不"刷新"它.
如何使用ngrx实现这一目标?
我正在使用效果.这是我的代码的样子:
组件:
export class EditPageComponent implements OnInit {
countries$: Observable<Country[]>
constructor(private store: Store<fromContacts.State>) {
this.countries$ = store.select(fromContacts.getCountriesEntities);
}
ngOnInit() {
this.store.dispatch(new countries.Load());
}
Run Code Online (Sandbox Code Playgroud)
效果:
@Effect()
loadCollection$: Observable<Action> = this.actions$
.ofType(countries.LOAD)
.switchMap(() =>
this.countriesService
.getCountries()
.map((countriesList: Country[]) => {
return new countries.LoadSuccess(countriesList);
})
.catch(error => of(new countries.LoadFail(error)))
);
Run Code Online (Sandbox Code Playgroud)
还原剂:
case countries.LOAD_SUCCESS: {
const countriesList: Country[] = action.payload;
const reducedCountries: { [id: string]: Country } = countriesList.reduce((countrs: { [id: string]: Country }, countr: Country) => {
return Object.assign(countrs, …Run Code Online (Sandbox Code Playgroud) 我一直在阅读ngrx示例应用程序的代码并找到两个函数调用
createFeatureSelector<AuthState>('auth'); 和
createSelector(selectAuthState,(state: AuthState) => state.status);这是做什么的?
export const selectAuthState = createFeatureSelector<AuthState>('auth');
export const selectAuthStatusState = createSelector(
selectAuthState,
(state: AuthState) => state.status
);
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用ngrx-store-localstorage将ngrx集成到我的身份验证过程中,以跨越浏览器会话存储令牌.
当我登录时,我可以在存储中看到令牌的价值
{"token":{"token":"e5cb6515-149c-44df-88d1-4ff16ff4169b","expiresIn":10385,"expiresAt":1512082478397},"authenticated":true,"error":false}
Run Code Online (Sandbox Code Playgroud)
但是当我编辑一个页面并重新加载我的应用程序时
{"token":null,"authenticated":false,"error":false}
Run Code Online (Sandbox Code Playgroud)
import { Action } from '@ngrx/store';
import { AuthenticationTokenInterface } from '../authentication.interface';
export const LOGIN = 'LOGIN';
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
export const LOGIN_FAILED = 'LOGIN_FAILED';
export const LOGOUT = 'LOGOUT';
export const SET_TOKEN = 'SET_TOKEN';
export class Login implements Action {
readonly type = LOGIN;
constructor(public payload: {username: 'string',password: 'string'}) {}
}
export class LoginSuccess implements Action {
readonly type = LOGIN_SUCCESS;
}
export class LoginFailed implements Action {
readonly type = …Run Code Online (Sandbox Code Playgroud) 我正在尝试为 Angular 中的服务编写单元测试。我想模拟 ngrx 的 store.select 函数,这样我就可以测试服务如何对存储选择器返回的不同值做出反应。我希望能够单独模拟每个选择器。
我的主要问题是如何模拟参数化选择器。
我之前使用过映射到 select 函数的 BehaviourSubject,但这不允许您为不同的选择器返回不同的值。它不可读,因为你正在嘲笑哪个选择器并不明显。
选项1:使用主题的模拟存储:无法知道主题对应哪个选择器,无法为不同的选择器返回不同的值。
// 服务.spec.ts
const selectSubject = new BehaviourSubject(null);
class MockStore {
select = () => selectSubject;
}
Run Code Online (Sandbox Code Playgroud)
选项2:使用开关模拟存储:适用于不同的选择器,但当选择器有参数时无法使其工作。
// 服务.spec.ts
// This works well but how can I make it work with selectors with parameters??
const firstSubject = new BehaviourSubject(null);
const secondSubject = new BehaviourSubject(null);
class MockStore {
select = (selector) => {
switch (selector): {
case FirstSelector: {
return firstSubject;
}
case SecondSelector: {
return secondSubject;
} …Run Code Online (Sandbox Code Playgroud) 我试图找出当服务器响应分页时如何设计 NgRx 存储。
如果我们一次在商店中只保留一页,那么使用 NgRx 到底有什么意义呢?
如果我们为所有页面保留插槽并在第一次调用该特定页面时填充存储中的每个页面,那么如何处理每个请求可能不同的 page_size,...查询参数。
如何处理 NgRx 中的过滤和排序。是否值得保留带有太多查询参数的响应?
我当前的界面就像
res : {
pagination: {
page: 1,
page_size: 25,
total_items: 10000,
total_pages: 400
},
data: [array of 25 objects]
}
Run Code Online (Sandbox Code Playgroud) 我有一个在构造函数中分派操作的组件:
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
constructor(store: Store<State>) {
store.dispatch(action1());
store.dispatch(action2());
}
}
Run Code Online (Sandbox Code Playgroud)
我需要测试 action1 和 action2 是否已调度。我正在尝试使用 MockStore 来做到这一点:
import {MockStore, provideMockStore} from '@ngrx/store/testing';
let store: MockStore;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
AppComponent
],
providers: [
provideMockStore({ initialState }),
],
}).compileComponents();
store = TestBed.inject(MockStore);
});
Run Code Online (Sandbox Code Playgroud)
这是我的测试:
it('should dispatch an action1 in constructor', () => {
TestBed.createComponent(AppComponent);
const expected = cold('a', {a: action1()});
expect(store.scannedActions$).toBeObservable(expected);
});
it('should dispatch an action2 in constructor', () …Run Code Online (Sandbox Code Playgroud) 我刚刚开始为我的应用程序编写e2e测试,并且遇到了Protractor和ngrx/effects的超时问题.
我每隔几分钟调度一次动作有以下效果:
@Effect() setSessionTimer$ = this.actions$
.ofType(Auth.ActionTypes.SET_SECONDS_LEFT)
.map(toPayload)
.switchMap(secondsLeft => Observable.concat(
Observable.timer((secondsLeft - 60) * 1000).map(_ => new Auth.SessionExpiringAction(60)),
Observable.timer(60 * 1000).map(_ => new Auth.SessionExpiredAction())
));
Run Code Online (Sandbox Code Playgroud)
尝试运行Protractor测试会导致测试超时并出现以下错误,因为Angular不稳定.
失败:超时等待异步Angular任务在11秒后完成.这可能是因为当前页面不是Angular应用程序.有关更多详细信息,请参阅常见问题解答:https: //github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular 在等待带定位符的元素时 - 定位器:By(css选择器,.工具栏标题)
根据这个问题(https://github.com/angular/protractor/issues/3349)我需要使用NgZone在Angular之外运行一个Observable区间.我尝试了不同的组合this.ngZone.runOutsideAngular()但没有工作,测试继续超时.
例如,这不起作用:
@Effect() setSessionTimer$ = this.actions$
.ofType(Auth.ActionTypes.SET_SECONDS_LEFT)
.map(toPayload)
.switchMap(secondsLeft => this.ngZone.runOutsideAngular(() => Observable.concat(
Observable.timer((secondsLeft - 60) * 1000).map(_ => new Auth.SessionExpiringAction(60)),
Observable.timer(60 * 1000).map(_ => new Auth.SessionExpiredAction())
)));
Run Code Online (Sandbox Code Playgroud)
我不知道如何在Angular之外运行效果.有没有人成功测试过他们的ngrx应用程序?
ngrx ×10
angular ×8
ngrx-store ×3
ngrx-effects ×2
redux ×2
store ×2
effects ×1
pagination ×1
protractor ×1
reducers ×1
rxjs ×1
unit-testing ×1
zone.js ×1