Skip to content

Immer wrappers around NgRx methods createReducer, on, and ComponentStore

License

Notifications You must be signed in to change notification settings

timdeschryver/ngrx-immer

This branch is up to date with main.

Folders and files

NameName
Last commit message
Last commit date

Latest commit

54da7a5 · Jan 3, 2025

History

34 Commits
Mar 13, 2024
Jan 3, 2025
Dec 26, 2020
Dec 21, 2020
Feb 14, 2024
Dec 21, 2020
Nov 6, 2021
Dec 21, 2020
Jan 28, 2021
Mar 14, 2024
Mar 13, 2024
Jan 3, 2025
Aug 12, 2021
Jan 3, 2025
Mar 13, 2024
Feb 15, 2024
Aug 23, 2021

Repository files navigation

ngrx-immer

Immer wrappers around NgRx methods to simplify mutating state

Installation

npm install ngrx-immer

Do not forget to install immer

Functions

createImmerReducer (@ngrx/store)

Creates an NgRx reducer, but allows you to mutate state without having to use to spread operator.

  • Use it when you want to go Immer all the way
  • Caveat, you have to return the state with each on method
import { createImmerReducer } from 'ngrx-immer/store';

const todoReducer = createImmerReducer(
	{ todos: [] },
	on(newTodo, (state, action) => {
		state.todos.push({ text: action.todo, completed: false });
		return state;
	}),
	on(completeTodo, (state, action) => {
		state.todos[action.index].completed = true;
		return state;
	}),
);

immerOn (@ngrx/store)

Creates an NgRx reducer, but allows you to mutate state without having to use to spread operator.

  • Use it when you want to go sprinkle a little bit of Immer for more complex cases
import { immerOn } from 'ngrx-immer/store';

const todoReducer = createReducer(
	{ todos: [] },
	on(newTodo, (state, action) => {
		return {
			...state,
			todos: [...state.todos, action.todo],
		};
	}),
	immerOn(completeTodo, (state, action) => {
		state.todos[action.index].completed = true;
	}),
);

ImmerComponentStore (@ngrx/component-store)

Wraps Immer around the Component Store updater and setState methods.

import { ImmerComponentStore } from 'ngrx-immer/component-store';

@Injectable()
export class MoviesStore extends ImmerComponentStore<MoviesState> {
	constructor() {
		super({ movies: [] });
	}

	readonly addMovie = this.updater((state, movie: Movie) => {
		state.movies.push(movie);
	});
}

immerPatchState (@ngrx/signals)

Important

Because @ngrx/signals is in developer preview, the immerPatchState function is also in developer preview. It is ready to try, but may change before becoming stable.

Provides an Immer-version of the patchState function from the @ngrx/signals package. In addition to partial state objects and updaters that update the state immutably, it accepts updater functions that update the state in a mutable manner. Similar to patchState, the immerPatchState function can be used to update the state of both SignalStore and SignalState.

const UserStore = signalStore(
	withState({
		user: { firstName: 'Konrad', lastName: 'Schultz' },
		address: { city: 'Vienna', zip: '1010' },
	}),
	withMethods((store) => ({
		setLastName(lastName: string): void {
			immerPatchState(store, (state) => {
				state.user.lastName = lastName;
			});
		},
		setCity(city: string): void {
			immerPatchState(store, (state) => {
				state.address.city = city;
			});
		},
	}))
);

Please note, that the updater function can only mutate a change without returning it or return an immutable state without mutable change.

This one is going to throw a runtime error:

// will throw because of both returning and mutable change
immerPatchState(userStore, (state) => {
	state.name.lastname = 'Sanders'; // mutable change
	return state; // returning state
});

immerReducer

Inspired by Alex Okrushko, immerReducer is a reducer method that uses the Immer produce method. This method is used by all the methods in ngrx-immer provides.

FAQ

Resources