Angular ngrx迁移错误&#34;属性&#39;选择&#39;类型&#39; Observable <state>&#39;&#34;

时间:2017-08-29 17:59:59

标签: angular ngrx ngrx-store

我正在尝试将现有的应用程序从ngrx v2迁移到v4,并且我在migration document中没有看到的情况遇到一些麻烦。迁移文档可以删除@ngrx / core,但我不知道如何处理从@ ngrx / core / add / operator / select导入的reducers并从Observable中选择。我收到错误&#34; Property&#39; select&#39;类型&#39; Observable&#39;&#34;不存在来自所有减速器。

/actions/action-with-payload.ts - 迁移的解决方法

import { Action } from '@ngrx/store';

export class ActionWithPayload implements Action {
    type: string;
    payload?: any;
}

/actions/users-list.ts

export class UsersListActions {
    static LOAD_USERS_LIST = '[UserManagement/Users List] Load Users List';
    loadUsersList(): ActionWithPayload {
        return {
            type: UsersListActions.LOAD_USERS_LIST
        };
    }

    static LOAD_USERS_LIST_SUCCESS = '[UserManagement/Users List] Load Users List Success';
    loadUsersListSuccess(users: User[]): ActionWithPayload {
        return {
            type: UsersListActions.LOAD_USERS_LIST_SUCCESS,
            payload: users
        };
    }
}

/reducers/users-list.ts

export interface UsersListState {
  loaded: boolean;
  loading: boolean;
  entities: User[];
}

const initialState: UsersListState = {
  loaded: false,
  loading: false,
  entities: [],
} 

export default function (state = initialState, action: ActionWithPayload): UsersListState {
  switch (action.type) {
    case UsersListActions.LOAD_USERS_LIST:
      return Object.assign({}, state, {
        loading: true
      });
    case UsersListActions.LOAD_USERS_LIST_SUCCESS:
      return Object.assign({}, state, {
        loaded: true,
        loading: false,
        entities: action.payload
      });
    default:
      return state;
  }
};

export function getLoaded() {
  return (state$: Observable<UsersListState>) => state$
    .select(s => s.loaded);
}

export function getLoading() {
  return (state$: Observable<UsersListState>) => state$
    .select(s => s.loading);
}

export function getUsers() {
  return (state$: Observable<UsersListState>) => state$
    .select(s => s.entities);
}

/reducers/index.ts

import usersListReducer, * as fromUsers from './users-list';

export interface UserManagementState {
    usersList: fromUsers.UsersListState,
};

export { usersListReducer }

export function getUsersListState() {
    return (state$: Observable<UserManagementState>) => state$
        .select(s => s.usersList);
}

export function getUsers() {
    return compose(fromUsers.getUsers(), getUsersListState());
}

export function getUsersLoaded() {
  return compose(fromUsers.getLoaded(), getUsersListState());
}

export function getUsersLoading() {
    return compose(fromUsers.getLoading(), getUsersListState());
}

/pages/user-list.page.ts

export class UserListPage {
    private users$: Observable<User[]>;
    private usersLoading$: Observable<boolean>;

    constructor(
        private store: Store<UserManagementState>,
    ) {
        this.users$ = store.let(getUsers());
        this.usersLoading$ = store.let(getUsersLoading());
    }
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';    
import { usersListReducer } from '/reducers';    
import { AppComponent }  from './app.component';

@NgModule({
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    AppRoutingModule,
    SharedModule.forRoot(),
    StoreModule.provideStore({
        usersList: usersListReducer,
        ...
    })
  ],
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  providers: [ 
    ...
  ]
})
export class AppModule { }

2 个答案:

答案 0 :(得分:1)

我不确定您为什么需要导入select。即使在版本2中,我也从未这样做过。我将尝试展示代码对于单个实体应该是什么样子。

import {
  Action,
  ActionReducerMap,
  createFeatureSelector,
  createSelector 
} from '@ngrx/store';

export function userReducer(state = initialState, action: ActionWithPayload): UsersListState {
  switch (action.type) {
    case UsersListActions.LOAD_USERS_LIST:
      return Object.assign({}, state, {
        loading: true
      });
    case UsersListActions.LOAD_USERS_LIST_SUCCESS:
      return Object.assign({}, state, {
        loaded: true,
        loading: false,
        entities: action.payload
      });
    default:
      return state;
  }
};

export const getLoadedState = (state: UsersListState) => state.loaded; 
export const getLoadingState = (state: UsersListState) => state.loading;
export const getEntitiesState = (state: UsersListState) => state.entities;

export userStateSelector = createFeatureSelector<UsersListState>('users');
export const loadedState = createSelector(userStateSelector, getLoadedState);
export const loadingState = createSelector(userStateSelector, getLoadingState);
export const userState = createSelector(userStateSelector, getEntitiesState);

模块

imports: StoreModule.forFeature('users', userReducer);

在组件使用中选择如下:

public users$: Observable<User[]>;
constructor(private userStore: Store<UsersListState>){
    this.users$ = this.userStore.select(userState);
}

可能存在很多编译错误,但这只是一个伪代码来解释你的工作原理。

您可以查看https://github.com/ngrx/platform/tree/master/example-app以获取详细示例。但就我个人而言,我很难理解它是如何运作的。如果你有兴趣的话,我本周末可能会写一篇博客。

答案 1 :(得分:0)

创建一个包含所有状态的接口,如下所示,

export interface CompanyAppStore {
    userState: UsersListState;
    employeeState: EmployesListState;
}

创建一个reducer工厂,它是所有Reducer的集合,如下所示

export const reducers: ActionReducerMap<CompanyAppStore> = {
    userState: userStateReducer.reducer,
    employeeState: employeeStateReducer.reducer
};

按以下方式导入减速器,

import * as userStateReducer from './user.state.reducer';
import * as employeeStateReducer from './employee.state.reducer';

您的组件可以使用在步骤1中创建的应用程序界面注入

constructor(private appStore: Store<CompanyAppStore>){ }

现在您可以使用

选择特定的州
this.appStore
      .select(states => states.userState)
      .subscribe(..)