You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NGRX Selector报错:Cannot read properties of undefined (reading 'x') 求助

NGRX独立组件模式下*ngrxLet绑定Observable触发TypeError问题

问题背景

正在学习NGRX,参考教程视频实践,当前使用Angular独立组件模式,已在main.ts中配置provideStore,路由中通过provideState提供customer状态与Effects。Redux控制台显示数据正常切换,但HTML中使用*ngrxLet绑定Observable时,每个Observable都触发错误:ERROR TypeError: Cannot read properties of undefined (reading 'x')。

已尝试使用hasOwnProperty校验、移除所有index.ts文件,均未解决问题。

相关代码

测试组件代码

@Component({
  selector: 'app-one',
  standalone: true,
  imports: [
    CommonModule,
    LetModule
  ],
  templateUrl: './one.component.html',
  styleUrls: ['./one.component.scss']
})
export class OneComponent implements OnInit {

  private store = inject(Store<AppStateInterface>);
  isLoading$: Observable<boolean> = this.store.select(customerLoadingSelector);
  customer$: Observable<Customer | null> = this.store.select(customerSelector);
  error$: Observable<string | null> = this.store.select(errorSelector);

  ngOnInit(): void {
    this.store.dispatch(getCustomer());
  }

}

HTML代码

<p *ngrxLet="isLoading$ as loading">loading: {{loading}}</p>
<p *ngrxLet="error$ as error">error: {{error}}</p>
<p *ngrxLet="customer$ as customer">customer: {{customer}}</p>

Actions代码

export const getCustomer = createAction('[Customer] get Customer');
export const getCustomerSuccess = createAction('[Customer] get Customer success', props<{ customer: Customer; }>());
export const getCustomerFailure = createAction('[Customer] get Customer failure', props<{ error: string; }>());

Reducer代码

export const initialState: CustomerStateInterface = {
  isLoading: false,
  customer: null,
  error: null
};

export const customerReducer = createReducer(
  initialState,
  on(getCustomer, (state) => ({ ...state, isLoading: true })),
  on(getCustomerSuccess, (state, action) => ({
    ...state,
    isLoading: false,
    customer: action.customer
  })),
  on(getCustomerFailure, (state, action) => ({
    ...state,
    isLoading: true,
    error: action.error
  }))
);

Selector代码

export const selectCustomer = (state: AppStateInterface) => state.customer;

export const customerLoadingSelector = createSelector(selectCustomer, (state: CustomerStateInterface) => state.isLoading);
export const customerSelector = createSelector(selectCustomer, (state: CustomerStateInterface) => state.customer);
export const errorSelector = createSelector(selectCustomer, (state: CustomerStateInterface) => state.error);

main.ts配置

bootstrapApplication(
  AppComponent,
  {
    providers: [
      provideRouter(routes),
      provideStore(),
      provideRouterStore(),
      provideStoreDevtools(
        {
          maxAge: 25,
          logOnly: environment.production,
          autoPause: true
        }
      ),
      importProvidersFrom(
        BrowserModule,
        HttpClientModule,
        IonicModule.forRoot(),
        TranslateModule.forRoot({
          loader: {
            provide: TranslateLoader,
            useFactory: (createTranslateLoader),
            deps: [HttpClient]
          }
        })
      )
    ]
  }
).catch(err => console.log(err));

路由配置

{
    path: 'test',
    providers: [
      provideState(customerFeatureKey, customerReducer),
      provideEffects(CustomerEffects)
    ],
    loadComponent: () => import('../pages/test/test.page').then(c => c.TestPage)
  }

问题分析与解决方案

出现错误的核心原因是:在路由级别提供Feature State时,组件初始化阶段AppStateInterface中的customer属性为undefined,而Selector直接尝试读取该属性的子字段(如isLoading),导致触发读取undefined属性的报错。Redux控制台显示数据正常切换是因为后续Action触发后Reducer会初始化该状态,但组件初始化时Selector已先执行了一次。

解决步骤:

  1. 在根Selector中添加空值兜底
    修改selectCustomer,当state.customer不存在时返回Reducer的初始状态,避免后续读取子字段出错:

    import { initialState } from './customer.reducer';
    
    export const selectCustomer = (state: AppStateInterface) => state.customer ?? initialState;
    
  2. 确保AppStateInterface定义规范
    检查AppStateInterface中customer属性的定义,若为可选属性需明确标注,或直接指定类型为CustomerStateInterface(而非可选),避免类型层面的undefined隐患:

    // 推荐写法:明确类型,无可选标识
    export interface AppStateInterface {
      customer: CustomerStateInterface;
    }
    
  3. 校验Feature Key一致性
    确认路由中使用的customerFeatureKey值,与AppStateInterface中customer键名、Reducer注册的key完全一致,避免因拼写错误导致状态无法正确映射。

验证方案

修改完成后,组件初始化时Selector会返回initialState,isLoading$将获取初始值false,customer$和error$获取null,此时*ngrxLet绑定不会再触发undefined错误,后续Action触发后状态更新也能正常显示。

内容的提问来源于stack exchange,提问作者Basti-V

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 22:01:03