Skip to main content

Reducers

Reducers are responsible for turning (currentState, action) into nextState.

In HexaJS, reducer classes use decorators:

  • @Reducer() on the class.
  • @Reduce(ACTION_TYPE) on each handler method.

Reducer example

import { HexaReducer, Reduce, Reducer } from '@hexajs-dev/core';
import * as BackgroundActions from './background.actions';

@Reducer()
export class LastContentCallReducer extends HexaReducer<LastContentCallState> {
initialState: LastContentCallState = {
message: '',
timestamp: 0,
};

@Reduce(BackgroundActions.CONTENT_CALLED)
onContentCalled(
state: LastContentCallState,
action: ReturnType<typeof BackgroundActions.contentCalled>
): LastContentCallState {
if (!action.payload?.message || !action.payload?.timestamp) {
return state;
}
return { ...action.payload };
}
}

Reducer rules

  • Return a new object when state changes.
  • Return state unchanged when payload is invalid or action is not applicable.
  • Keep reducer methods deterministic and side-effect free.
  • Perform logging/IO in services/controllers/handlers, not reducers.

CLI and compiler behavior

  • Use hexa generate reducer <name> <context> to scaffold reducer classes.
  • Use hexa generate state <name> <context> to register reducer slices under @State(...).
  • The CLI scanner (packages/cli/src/compiler/store/reducer/scanner.ts) discovers reducer metadata during build.

Where reducers are used

Reducers power both:

  • Background store transitions driven by controllers/actions.
  • Content store transitions driven by handlers/actions.