9

Looked around the web and can't find an example of using import produce, {Draft} from "immer"; with the ngrx on() the closest I can find is: a non complete solution on: https://github.com/immerjs/immer/issues/252

import produce, { Draft } from 'immer';
import { ActionCreator, createReducer, on } from '@ngrx/store';
import { ActionType, FunctionWithParametersType } from '@ngrx/store/src/models';

function produceOn<Type extends string, C extends FunctionWithParametersType<any, object>, State>(
  actionType: ActionCreator<Type, C>,
  callback: (draft: Draft<State>, action: ActionType<ActionCreator<Type, C>>) => any,
) {
  return on(actionType, (state: State, action): State => produce(state, (draft) => callback(draft, action)));
}

// Usage:

const featureReducer = createReducer(
  initialState,
  produceOn(action, (draft, action) => {
     // TODO STUFF
  }
);

export function reducer(state = initialState, action) {
  return featureReducer(state, action);
}

not sure how to incoperate the on() with immer with ngrx 8

Sean.

born2net
  • 24,129
  • 22
  • 65
  • 104

2 Answers2

11

found the answer:

import {createReducer} from '@ngrx/store';
import {on} from "@ngrx/store";
import produce, {Draft} from "immer";

export const initialUserState: IUserState = {
    knownUsers: [user1, user2],
    selectedUser: null,
    scenes: null
};

export function produceOn<Type extends string, C extends FunctionWithParametersType<any, object>, State>(
    actionType: ActionCreator<Type, C>,
    callback: (draft: Draft<State>, action: ActionType<ActionCreator<Type, C>>) => any,
) {return on(actionType, (state: State, action): State => produce(state, (draft) => callback(draft, action)));}

export const loadRequest = createAction('[Scenes API] Scene Load Request', props<{ businessId: BusinessId }>());
export const loadSuccess = createAction('[Scenes API] Scene Load Success', props<{ scenes: List<SceneModel> }>());

// ngrx 8+ with immer and support for on() within reducer

const featureReducer = createReducer(
    initialUserState,
    produceOn(loadSuccess, (draft, action) => {
        draft.scenes = {myList: [1,2,3]};
    }),
    produceOn(loadFailure, (draft, action) => {
        draft.scenes = {myList: []};
        console.log('error loading...');
    })
);
born2net
  • 24,129
  • 22
  • 65
  • 104
  • 4
    just posting a link to your discussion on immer's github as it's relevant to people here and theres no link through: https://github.com/immerjs/immer/issues/252 Notably, the last comment, ngrx-etc library is built with immer and gives essentially your method. https://github.com/timdeschryver/ngrx-etc – James Sep 26 '19 at 10:38
7

There is an repo from a ngrx-maintainer https://github.com/timdeschryver/ngrx-etc which gives you a mutableOn function, which can be used like here

mutableOn(increment, (state, {incrementBy}) => {
  state.count += incrementBy;
})
Bene
  • 874
  • 1
  • 10
  • 15