问题描述
我有一个大型项目正在慢慢迁移到新的 ngrx
语法。我们有很多选择器都是像这样的普通函数:
export function appDetailsSelector(state$: Observable<AppState>): Observable<AppDetails> {
return state$.pipe(map((appState: AppState) => appState.appDetails));
}
使用 createSelector
编写新的选择器:
export const selectUserConfig: MemoizedSelector<AppState,UserConfig> = createSelector(
selectUserData,(userData: UserData) => userData.config,);
这两个都使用相同的状态形状,但是我如何组合以创建一个将这两个与 createSelector
组合在一起的新选择器?
我知道我可以在组件代码中使用管道来做到这一点:
combineLatest([
this.store.pipe(appDetailsSelector),this.store.select(selectUserConfig),],(appDetails,userConfig) => ...projector fn code...);
但这不是可重用的,我需要用 createSelector
完成以避免在多个组件中重复此操作。如果 appDetailsSelector
是用 createSelector
创建的,它看起来像这样:
export const getUserBookmarks = createSelector(
appDetailsSelector,selectUserConfig,(appDetails: AppDetails,userConfig: UserConfig) => appDetails.useBookmarks ? userConfig.bookmarks : []
);
但是这个Argument of type 'MemoizedSelector<AppState,UserConfig,DefaultProjectorFn<UserConfig>>' is not assignable to parameter of type 'SelectorWithProps<Observable<AppState>,unkNown,UserConfig>'. Types of parameters 'state' and 'state' are incompatible. Type 'Observable<AppState>' is missing the following properties from type 'AppState'...
我可以看到旧式选择器采用 Observable<AppState>
,而新式选择器采用 AppState
;如何弥合这一差距并结合这两个选择器?
解决方法
您可以使用类型转换
export const getUserBookmarks = createSelector(
appDetailsSelector as MemoizedSelector<AppState,UserConfig,DefaultProjectorFn<UserConfig>>,selectUserConfig as MemoizedSelector<AppState,(appDetails: AppDetails,userConfig: UserConfig) => appDetails.useBookmarks ? userConfig.bookmarks : []
);
Typecasting 会将类型设置为相同的类型
,无法将 Observable
选择器与新的 createSelector
语法一起使用。 Observable 选择器对 observable 进行操作,而函数选择器直接对 observable 中包含的数据进行操作;没有开箱即用的方法可以让它们协同工作。
注意,observable 选择器实际上是变相的函数选择器;如果您需要维护经典选择器,只需将有状态逻辑移出到函数选择器中,并在每个上下文中使用正确的选择器。
export const appDetailsSelector = (state: AppState) => state.appDetails;
export const appDetailsObservableSelector = (state$: Observable<AppState>) =>
state$.pipe(map(appDetailsSelector));