This content originally appeared on Bits and Pieces - Medium and was authored by Daniel Glejzner
Handle immutability in NgRx reducers with the ngrx-immer library.
NgRx is a popular state management library for Angular applications. It provides a centralized store for storing the application’s state and a set of tools for updating the state in a predictable manner. NgRx also provides a powerful set of reducers, which are functions that specify how the state should change in response to an action.
One of the core concepts in NGRX is immutability, which means that the state should never be modified directly. Instead, when an action is dispatched, the reducer creates a new copy of the state with the necessary changes. This helps ensure that the state remains predictable and that it can be easily tested and debugged.
However, creating a new copy of the state can be quite a pain, especially for complex state structures. To address this issue, ngrx-immer was created, which is a library that provides an easier way to handle immutability in NgRx reducers.
NgRx on method vs immerOn method
Consider a state with a list of users, where each user has a name and an age. We want to add a new user to the list, update the name of an existing user, and delete a user from the list.
Using the on method, we would write the following NGRX reducer:
import { createReducer, on } from '@ngrx/store';
import { addUser, updateUser, deleteUser } from './user.actions';
export interface User {
name: string;
age: number;
}
export const initialState: User[] = [];
export const _userReducer = createReducer(
initialState,
on(addUser, (state, { user }) => [...state, user]),
on(updateUser, (state, { user, name }) =>
state.map(u => (u.name === user.name ? { ...u, name } : u))
),
on(deleteUser, (state, { user }) =>
state.filter(u => u.name !== user.name)
)
);
Using the immerOn method from ngrx-immer, we would write the following NgRx reducer:
import { createReducer, immerOn } from 'ngrx-immer';
import { addUser, updateUser, deleteUser } from './user.actions';
export interface User {
name: string;
age: number;
}
export const initialState: User[] = [];
export const _userReducer = createReducer(
initialState,
immerOn(addUser, (state, { user }) => {
state.push(user);
}),
immerOn(updateUser, (state, { user, name }) => {
const index = state.findIndex(u => u.name === user.name);
state[index].name = name;
}),
immerOn(deleteUser, (state, { user }) => {
const index = state.findIndex(u => u.name === user.name);
state.splice(index, 1);
})
);
As you can see, the immerOn method provides a more intuitive and direct way of updating the state. It allows you to modify the state directly instead of creating a new object with the spread operator.
You don’t have to refactor your app — mix and match!
No need to rewrite all of your reducers.
You can use immerOn in the places that are the most complicated.
You can combine the immerOn method from the ngrx-immer library with the on method from the @ngrx/store library.
import { createReducer, on, immerOn } from 'ngrx-immer';
import { addUser, updateUser, deleteUser, togglePremium } from './user.actions';
export interface User {
name: string;
age: number;
premium: boolean;
}
export const initialState: User[] = [];
export const _userReducer = createReducer(
initialState,
on(addUser, (state, { user }) => [...state, user]),
immerOn(updateUser, (state, { user, name }) => {
const index = state.findIndex(u => u.name === user.name);
state[index].name = name;
}),
immerOn(deleteUser, (state, { user }) => {
const index = state.findIndex(u => u.name === user.name);
state.splice(index, 1);
}),
immerOn(togglePremium, (state, { user }) => {
const index = state.findIndex(u => u.name === user.name);
state[index].premium = !state[index].premium;
})
);
Almost no effort to use but makes a giant difference to your code readability and complexity.
Worthy of becoming part of the NgRx core library?
Do you think this should become a part of the core NgRx library? I vote that it should!
Why?
Installing multiple dependencies maintained outside of core libraries is always a risk of something that can stop being maintained.
Smaller lib, less maintainers = bigger risk.
And something as useful as this could come in a bundle with NgRx.
Don’t agree? Let’s discuss.
Sources
All credits go to fantastic Tim Deschryver — the author of this library.
Build Angular Apps with reusable components, just like Lego
Bit’s open-source tool help 250,000+ devs to build apps with components.
Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.
Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:
→ Micro-Frontends
→ Design System
→ Code-Sharing and reuse
→ Monorepo
Learn more:
- Introducing Angular Component Development Environment
- 10 Useful Angular Features You’ve Probably Never Used
- 11 Top Angular Developer Tools for 2020
- How We Build Micro Frontends
- How to Share Angular Components Between Projects and Apps
- How we Build a Component Design System
Make Your Angular NgRx Reducers an Eye Candy 🍬 Using this Fantastic Library was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Bits and Pieces - Medium and was authored by Daniel Glejzner
Daniel Glejzner | Sciencx (2023-04-14T13:09:14+00:00) Make Your Angular NgRx Reducers an Eye Candy Using this Fantastic Library. Retrieved from https://www.scien.cx/2023/04/14/make-your-angular-ngrx-reducers-an-eye-candy-using-this-fantastic-library/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.