Angular+ngrx:如何在路由器 url 遍历时保持存储状态?
Angular+ngrx: how to keep store state on router url traversing?
我知道每次用户刷新页面时存储都会重置(所谓的 "hard refresh"),但我希望当用户使用 angular 路由器遍历页面时它保持不变。但是,正如我所见,它无论如何都会重置。
我错了吗?有没有什么方法可以在不保存到 LocalStorage 或使用其他技巧的情况下保留存储?
app.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
// Routing
import { AppRoutingModule } from './app-routing.module';
// Ngrx
import { StoreModule } from '@ngrx/store';
import {
StoreRouterConnectingModule,
RouterStateSerializer,
} from '@ngrx/router-store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { EffectsModule } from '@ngrx/effects';
// Other
import { reducers, metaReducers } from './core/reducers';
import { CustomRouterStateSerializer } from './core/utils/router.utils';
import { MaterialModule } from './material/material.module';
// Environment
import { environment } from '../environments/environment';
// Components
import { AppComponent } from './app.component';
import { NotFoundComponent } from './core/components/not-found.component';
import { NotAuthorizedComponent } from './core/components/not-authorized.component';
import { HomeComponent } from './core/components/home.component';
import { UsersModule } from './users/users.module';
import { EventsModule } from "./events/events.module";
@NgModule({
declarations: [
AppComponent,
NotFoundComponent,
HomeComponent,
NotAuthorizedComponent,
],
imports: [
CommonModule,
HttpClientModule,
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
MaterialModule,
StoreModule.forRoot(reducers, { metaReducers }),
StoreRouterConnectingModule.forRoot({stateKey: 'router'}),
StoreDevtoolsModule.instrument(),
EffectsModule.forRoot([]),
UsersModule,
EventsModule
],
providers: [
{ provide: RouterStateSerializer, useClass: CustomRouterStateSerializer },
],
bootstrap: [AppComponent]
})
export class AppModule { }
./core/reducers/index.ts
import {
ActionReducerMap,
ActionReducer,
MetaReducer, createFeatureSelector, createSelector,
} from '@ngrx/store';
import { environment } from '../../../environments/environment';
import { RouterStateUrl } from '../utils/router.utils';
import * as fromRouter from '@ngrx/router-store';
import * as fromAuth from '../../users/reducers/auth.reducer';
import { storeFreeze } from 'ngrx-store-freeze';
export interface State {
router: fromRouter.RouterReducerState<RouterStateUrl>,
auth: fromAuth.State;
}
export const reducers: ActionReducerMap<State> = {
router: fromRouter.routerReducer,
auth: fromAuth.reducer
};
export function logger(reducer: ActionReducer<State>): ActionReducer<State> {
return function(state: State, action: any): State {
console.log('state', state);
console.log('action', action);
return reducer(state, action);
};
}
export const metaReducers: MetaReducer<State>[] = !environment.production
? [logger, storeFreeze]
: [];
// AUTH reducers
export const selectAuthState = createFeatureSelector<fromAuth.State>('auth');
export const getUser = createSelector(
selectAuthState,
fromAuth.getUser
);
export const getLoaded = createSelector(
selectAuthState,
fromAuth.getLoaded
);
export const getError = createSelector(
selectAuthState,
fromAuth.getError
);
想法是通过 HTTP GET 从服务器获取用户凭据,将它们放在存储中,然后从存储而不是服务器中获取它们。所以我有一个守卫:
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private store: Store<State>, protected router: Router) {
}
protected getFromStoreOrAPI(): Observable<any> {
return this.store
.select(getUser)
.do(user => {
if (!user) this.store.dispatch(new Signin());
})
.filter(user => user)
.take(1);
}
canActivate(): Observable<boolean> {
return this.getFromStoreOrAPI()
.switchMap(() => Observable.of(true))
.catch(() => Observable.of(false));
}
}
在 this.store.dispatch(new Signin());
它进行 HTTP 调用并将数据存入存储。
问题是,每次用户转到新页面时它都会进行 HTTP 调用。
检查你的减速器,我确定你犯了一个错误,忘记了 return 状态在你的 switch 语句中:
switch(action.type){
...
default:
return state;
}
我真傻!使用 <a href="/link">Link</a>
而不是 <a routerLink="/link">Link</a>
!
我知道每次用户刷新页面时存储都会重置(所谓的 "hard refresh"),但我希望当用户使用 angular 路由器遍历页面时它保持不变。但是,正如我所见,它无论如何都会重置。
我错了吗?有没有什么方法可以在不保存到 LocalStorage 或使用其他技巧的情况下保留存储?
app.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
// Routing
import { AppRoutingModule } from './app-routing.module';
// Ngrx
import { StoreModule } from '@ngrx/store';
import {
StoreRouterConnectingModule,
RouterStateSerializer,
} from '@ngrx/router-store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { EffectsModule } from '@ngrx/effects';
// Other
import { reducers, metaReducers } from './core/reducers';
import { CustomRouterStateSerializer } from './core/utils/router.utils';
import { MaterialModule } from './material/material.module';
// Environment
import { environment } from '../environments/environment';
// Components
import { AppComponent } from './app.component';
import { NotFoundComponent } from './core/components/not-found.component';
import { NotAuthorizedComponent } from './core/components/not-authorized.component';
import { HomeComponent } from './core/components/home.component';
import { UsersModule } from './users/users.module';
import { EventsModule } from "./events/events.module";
@NgModule({
declarations: [
AppComponent,
NotFoundComponent,
HomeComponent,
NotAuthorizedComponent,
],
imports: [
CommonModule,
HttpClientModule,
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
MaterialModule,
StoreModule.forRoot(reducers, { metaReducers }),
StoreRouterConnectingModule.forRoot({stateKey: 'router'}),
StoreDevtoolsModule.instrument(),
EffectsModule.forRoot([]),
UsersModule,
EventsModule
],
providers: [
{ provide: RouterStateSerializer, useClass: CustomRouterStateSerializer },
],
bootstrap: [AppComponent]
})
export class AppModule { }
./core/reducers/index.ts
import {
ActionReducerMap,
ActionReducer,
MetaReducer, createFeatureSelector, createSelector,
} from '@ngrx/store';
import { environment } from '../../../environments/environment';
import { RouterStateUrl } from '../utils/router.utils';
import * as fromRouter from '@ngrx/router-store';
import * as fromAuth from '../../users/reducers/auth.reducer';
import { storeFreeze } from 'ngrx-store-freeze';
export interface State {
router: fromRouter.RouterReducerState<RouterStateUrl>,
auth: fromAuth.State;
}
export const reducers: ActionReducerMap<State> = {
router: fromRouter.routerReducer,
auth: fromAuth.reducer
};
export function logger(reducer: ActionReducer<State>): ActionReducer<State> {
return function(state: State, action: any): State {
console.log('state', state);
console.log('action', action);
return reducer(state, action);
};
}
export const metaReducers: MetaReducer<State>[] = !environment.production
? [logger, storeFreeze]
: [];
// AUTH reducers
export const selectAuthState = createFeatureSelector<fromAuth.State>('auth');
export const getUser = createSelector(
selectAuthState,
fromAuth.getUser
);
export const getLoaded = createSelector(
selectAuthState,
fromAuth.getLoaded
);
export const getError = createSelector(
selectAuthState,
fromAuth.getError
);
想法是通过 HTTP GET 从服务器获取用户凭据,将它们放在存储中,然后从存储而不是服务器中获取它们。所以我有一个守卫:
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private store: Store<State>, protected router: Router) {
}
protected getFromStoreOrAPI(): Observable<any> {
return this.store
.select(getUser)
.do(user => {
if (!user) this.store.dispatch(new Signin());
})
.filter(user => user)
.take(1);
}
canActivate(): Observable<boolean> {
return this.getFromStoreOrAPI()
.switchMap(() => Observable.of(true))
.catch(() => Observable.of(false));
}
}
在 this.store.dispatch(new Signin());
它进行 HTTP 调用并将数据存入存储。
问题是,每次用户转到新页面时它都会进行 HTTP 调用。
检查你的减速器,我确定你犯了一个错误,忘记了 return 状态在你的 switch 语句中:
switch(action.type){
...
default:
return state;
}
我真傻!使用 <a href="/link">Link</a>
而不是 <a routerLink="/link">Link</a>
!