The way to do this is to have an auxiliary gearbox that processes the auxiliary part of the state tree.
In the case when you need to send actions to one element of the array, you pass all these actions to the second reducer, which processes one element.
Here is an example news item that has comments. I hope this makes it a little easier.
import { Action } from '@ngrx/store'; import { AppState } from '../reducer'; import { NewsItem } from './news.model'; import * as newsActions from './news.actions'; export interface NewsState { readonly loading: boolean; readonly entities: NewsItem[]; } export interface AppStateWithNews extends AppState { readonly news: NewsState; } const initialState: NewsState = { loading: false, entities: [], }; const newsItemReducer = (newsItem: NewsItem, action: newsActions.NewsActionTypes): NewsItem => { switch (action.type) { case newsActions.Types.UPDATE: case newsActions.Types.REMOVE: case newsActions.Types.COMMENT_CREATE: case newsActions.Types.COMMENT_REMOVE: return Object.assign({}, newsItem, { action: true }); case newsActions.Types.UPDATE_SUCCESS: return Object.assign({}, action.payload, { action: false }); case newsActions.Types.COMMENT_CREATE_SUCCESS: return Object.assign({}, newsItem, { action: false, comments: [action.payload.comment, ...newsItem.comments] }); case newsActions.Types.COMMENT_REMOVE_SUCCESS: return Object.assign({}, newsItem, { action: false, comments: newsItem.comments.filter(i => i.id !== action.payload.commentId) }); default: return newsItem; } }; export const newsReducer = (state: NewsState = initialState, action: newsActions.NewsActionTypes): NewsState => { switch (action.type) { case newsActions.Types.LIST: return Object.assign({}, state, { loading: true }); case newsActions.Types.LIST_SUCCESS: return { loading: false, entities: action.payload }; case newsActions.Types.CREATE_SUCCESS: return Object.assign({ loading: false, entities: [action.payload, ...state.entities] }); case newsActions.Types.REMOVE_SUCCESS: return Object.assign({ loading: false, entities: state.entities.filter(newsItem => newsItem !== action.payload) });
And see what it's called here - news.actions.
import { Action } from '@ngrx/Store'; import { NewsItem } from './news.model'; import { Response } from '@angular/http'; export const Types = { LIST: '[News] List', LIST_SUCCESS: '[News] List Success', LIST_ERROR: '[News] List ERROR', CREATE: '[News] Create', CREATE_SUCCESS: '[News] Create Success', CREATE_ERROR: '[News] Create Error', UPDATE: '[News] Update', UPDATE_SUCCESS: '[News] Update Success', UPDATE_ERROR: '[News] Update Error', REMOVE: '[News] Remove', REMOVE_SUCCESS: '[News] Remove Success', REMOVE_ERROR: '[News] Remove Error', COMMENT_CREATE: '[News] Comment Create', COMMENT_CREATE_SUCCESS: '[News] Comment Create Success', COMMENT_CREATE_ERROR: '[News] Comment Create Error', COMMENT_REMOVE: '[News] Comment Remove', COMMENT_REMOVE_SUCCESS: '[News] Comment Remove Success', COMMENT_REMOVE_ERROR: '[News] Comment Remove Error', }; export class List implements Action { type = Types.LIST; constructor(public payload?: any) {} } export class ListSuccess implements Action { type = Types.LIST_SUCCESS; constructor(public payload: NewsItem[]) {} } export class ListError implements Action { type = Types.LIST_ERROR; constructor(public payload: Response) {} } export class Create implements Action { type = Types.CREATE; constructor(public payload: NewsItem) {} } export class CreateSuccess implements Action { type = Types.CREATE_SUCCESS; constructor(public payload: NewsItem) {} } export class CreateError implements Action { type = Types.CREATE_ERROR; constructor(public payload: Response) {} } export class Update implements Action { type = Types.UPDATE; constructor(public payload: NewsItem) {} } export class UpdateSuccess implements Action { type = Types.UPDATE_SUCCESS; constructor(public payload: NewsItem) {} } export class UpdateError implements Action { type = Types.UPDATE_ERROR; constructor(public payload: Response) {} } export class Remove implements Action { type = Types.REMOVE; constructor(public payload: NewsItem) {} } export class RemoveSuccess implements Action { type = Types.REMOVE_SUCCESS; constructor(public payload: NewsItem) {} } export class RemoveError implements Action { type = Types.REMOVE_ERROR; constructor(public payload: Response) {} } export class CommentCreate implements Action { type = Types.COMMENT_CREATE; payload: { newsItem: NewsItem, comment: string }; constructor(newsItem: NewsItem, comment: string) { this.payload = { newsItem, comment }; } } export class CommentCreateSuccess implements Action { type = Types.COMMENT_CREATE_SUCCESS; payload: { newsItem: NewsItem, comment: string }; constructor(newsItem: NewsItem, comment: string) { this.payload = { newsItem, comment }; } } export class CommentCreateError implements Action { type = Types.COMMENT_CREATE_ERROR; constructor(public payload: Response) {} } export class CommentRemove implements Action { type = Types.COMMENT_REMOVE; payload: { newsItem: NewsItem, commentId: string }; constructor(newsItem: NewsItem, commentId: string) { this.payload = { newsItem, commentId }; } } export class CommentRemoveSuccess implements Action { type = Types.COMMENT_REMOVE_SUCCESS; payload: { newsItem: NewsItem, commentId: string }; constructor(newsItem: NewsItem, commentId: string) { this.payload = { newsItem, commentId }; } } export class CommentRemoveError implements Action { type = Types.COMMENT_REMOVE_ERROR; constructor(public payload: Response) {} } export type NewsActionTypes = List | ListSuccess | ListError | Create | CreateSuccess | CreateError | Update | UpdateSuccess | UpdateError | Remove | RemoveSuccess | RemoveError | CommentCreate | CommentCreateSuccess | CommentCreateError | CommentRemove | CommentRemoveSuccess | CommentRemoveError;