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

使用@ngrx/store添加对象到状态数组后,组件无法渲染更新内容的问题

Hey there! Let's dig into why your @ngrx/store notifications aren't showing up in the template. This is a super common gotcha with NgRx, usually tied to immutability or subscription missteps. Let's break it down step by step:

1. First, Fix the Immutability Issue (Most Likely Culprit)

NgRx relies entirely on immutable state updates—if you mutate the existing state array instead of returning a brand new one, Angular's change detection won't pick up the change, which is why your *ngFor doesn't re-run and length stays the same.

❌ Wrong Way (Mutating the Existing Array)

// notification.reducer.ts
case NotificationActions.AddNotification:
  // This mutates the original state array—NgRx won't detect this change
  state.notifications.push(action.payload);
  return state;

✅ Correct Way (Return New State with New Array)

// notification.reducer.ts
case NotificationActions.AddNotification:
  // Spread the existing state and create a new array with the new item
  return {
    ...state,
    notifications: [...state.notifications, action.payload]
  };

The spread operators (...) ensure we're creating new objects/arrays instead of modifying the original state reference.

2. Verify Your Component is Subscribed Correctly

Make sure your component is actually listening to the store's state changes. The async pipe is the recommended approach (it handles subscriptions and cleanup automatically):

Component Code

// notification-show.component.ts
import { Store } from '@ngrx/store';
import { select } from '@ngrx/store';
import { AppState } from '../state/app.state';
import { selectAllNotifications } from '../state/notification.selectors';

// Define an observable for the notifications
notifications$ = this.store.pipe(select(selectAllNotifications));

constructor(private store: Store<AppState>) {}

Template Code

<!-- notification-show.component.html -->
<!-- Use async pipe to subscribe to the observable -->
<div *ngFor="let notification of notifications$ | async">
  {{ notification.message }} <!-- Replace with your notification properties -->
</div>

<!-- Check length with the async pipe too -->
<p>Total notifications: {{ (notifications$ | async)?.length }}</p>

If you're using a manual subscription, don't forget to clean it up to avoid memory leaks:

// notification-show.component.ts
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

private destroy$ = new Subject<void>();
notifications: Notification[] = [];

ngOnInit() {
  this.store.pipe(
    select(selectAllNotifications),
    takeUntil(this.destroy$) // Unsubscribe when component is destroyed
  ).subscribe(notifications => {
    this.notifications = notifications;
  });
}

ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
}
3. Double-Check Your Selectors & State Setup

Ensure your selectors are pointing to the correct slice of your app state:

App State Interface

// app.state.ts
export interface AppState {
  notifications: NotificationState; // Match the key used when registering your reducer
}

export interface NotificationState {
  notifications: Notification[]; // The array holding your notifications
}

Selector Definition

// notification.selectors.ts
import { createFeatureSelector, createSelector } from '@ngrx/store';
import { NotificationState } from './notification.state';

// Get the root notification state slice
const selectNotificationState = createFeatureSelector<NotificationState>('notifications');

// Select the actual notifications array
export const selectAllNotifications = createSelector(
  selectNotificationState,
  (state: NotificationState) => state.notifications
);

Reducer Registration

Confirm your reducer is registered under the correct key in your store module:

// app.module.ts
import { StoreModule } from '@ngrx/store';
import { notificationReducer } from './state/notification.reducer';

@NgModule({
  imports: [
    StoreModule.forRoot({
      notifications: notificationReducer // Key matches the feature selector name
    })
  ]
})
export class AppModule {}
4. Confirm You're Dispatching the Action Correctly

Make sure you're sending the right payload when dispatching the add action:

Action Definition

// notification.actions.ts
import { createAction, props } from '@ngrx/store';
import { Notification } from './notification.model';

export const addNotification = createAction(
  '[Notification] Add Notification',
  props<{ notification: Notification }>() // Payload structure matches what you'll dispatch
);

Dispatching the Action

// In any component/service where you add notifications
import { Store } from '@ngrx/store';
import { addNotification } from '../state/notification.actions';

constructor(private store: Store<AppState>) {}

addNewNotification() {
  const newNotification: Notification = {
    id: Date.now(),
    message: 'This is a new notification!'
  };
  // Dispatch with the correct payload structure
  this.store.dispatch(addNotification({ notification: newNotification }));
}
Quick Debugging Tricks
  • Add console.log in your reducer to confirm the action is being caught and the new state is returned correctly.
  • Use the tap operator in your component to log the notifications stream:
    notifications$ = this.store.pipe(
      select(selectAllNotifications),
      tap(notifications => console.log('Current notifications:', notifications))
    );
    
  • Use Redux DevTools to inspect state changes—this lets you visually confirm if the state updates when you dispatch the action.

内容的提问来源于stack exchange,提问作者Developer Team

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:55:56