<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Moussa Sow</title>
    <description>The latest articles on DEV Community by Moussa Sow (@cheikhbethio).</description>
    <link>https://dev.to/cheikhbethio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F568902%2F96d54abf-8902-4851-bec8-d2f1edc3fae8.jpeg</url>
      <title>DEV Community: Moussa Sow</title>
      <link>https://dev.to/cheikhbethio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cheikhbethio"/>
    <language>en</language>
    <item>
      <title>Angular NgRx + LocalStorage</title>
      <dc:creator>Moussa Sow</dc:creator>
      <pubDate>Fri, 09 May 2025 14:37:58 +0000</pubDate>
      <link>https://dev.to/cheikhbethio/angular-ngrx-localstorage-34fl</link>
      <guid>https://dev.to/cheikhbethio/angular-ngrx-localstorage-34fl</guid>
      <description>&lt;p&gt;This Angular 19 application includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stock management&lt;/strong&gt; (products, quantities, etc.).&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;shopping cart system&lt;/strong&gt; for adding/removing products.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent authentication&lt;/strong&gt; (token/user saved in localStorage).&lt;/li&gt;
&lt;li&gt;Optimized usage of &lt;strong&gt;NgRx Store&lt;/strong&gt; (global state) + &lt;strong&gt;ComponentStore&lt;/strong&gt; (light local state).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📦 Key Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  🔐 Authentication
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;User login (stores &lt;code&gt;token&lt;/code&gt; and &lt;code&gt;user&lt;/code&gt; in &lt;strong&gt;localStorage&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;Persistence via a &lt;strong&gt;custom MetaReducer&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;auth&lt;/code&gt; slice is restored on startup.&lt;/li&gt;
&lt;li&gt;Auth data is automatically saved after each action.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  🗃️ Stock Management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Product list (with quantity, price, etc.).&lt;/li&gt;
&lt;li&gt;Add, edit, delete products.&lt;/li&gt;
&lt;li&gt;State managed with &lt;strong&gt;NgRx Store&lt;/strong&gt; (&lt;code&gt;stock&lt;/code&gt; slice).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛒 Shopping Cart
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add/remove products from the cart.&lt;/li&gt;
&lt;li&gt;Dynamic total calculation.&lt;/li&gt;
&lt;li&gt;Cart state handled with &lt;strong&gt;ComponentStore&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Lighter and faster for UI interactions.&lt;/li&gt;
&lt;li&gt;Optional local persistence.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://nodejs.org/" rel="noopener noreferrer"&gt;Node.js&lt;/a&gt; (which includes npm)&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://angular.io/cli" rel="noopener noreferrer"&gt;Angular CLI&lt;/a&gt;: &lt;code&gt;npm install -g @angular/cli&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Clone the repository (if applicable):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/cheikhbethio/ngrx-2025.git
&lt;span class="nb"&gt;cd &lt;/span&gt;ngrx-2025
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install dependencies:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Run the development server:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng serve &lt;span class="nt"&gt;-o&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The application will be available at &lt;code&gt;http://localhost:4500/&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Core Concepts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Angular:&lt;/strong&gt; The application is built using the Angular framework.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;NgRx:&lt;/strong&gt; State management is handled using NgRx, following the Redux pattern (Actions, Reducers, Selectors, Store).

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;State:&lt;/strong&gt; Defined in &lt;code&gt;src/app/core/store/reducers/reducers.type.ts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Actions:&lt;/strong&gt; Trigger state changes (e.g., &lt;code&gt;src/app/core/store/actions/&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Reducers:&lt;/strong&gt; Handle state transitions based on actions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Selectors:&lt;/strong&gt; Retrieve specific pieces of state for components.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Services:&lt;/strong&gt; Angular services (&lt;code&gt;src/app/core/services/&lt;/code&gt;) encapsulate business logic like authentication.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project Structure (Partial)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── app/
│   ├── core/
│   │   ├── services/       # Application-wide services (e.g., AuthService)
│   │   ├── store/          # NgRx state management files
│   │   │   ├── actions/
│   │   │   ├── reducers/
│   │   │   ├── selectors/
│   │   │   └── effects/      # (If using @ngrx/effects)
│   │   └── types/          # Core data types/interfaces
│   ├── features/         # (Likely location for feature modules/components)
│   │   ├── auth/
│   │   ├── products/
│   │   └── basket/
│   ├── shared/           # Shared components, directives, pipes
│   ├── app.component.ts
│   ├── app.config.ts     # Main application configuration
│   └── app.routes.ts     # Application routing
├── assets/               # Static assets (images, etc.)
└── environments/         # Environment configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Description
&lt;/h2&gt;

&lt;p&gt;Together we go through all the code&lt;br&gt;
Let's start with the main entry of the code&lt;/p&gt;
&lt;h3&gt;
  
  
  app.component
&lt;/h3&gt;

&lt;p&gt;Okay, let's check the contents of &lt;code&gt;src/app/app.component.ts&lt;/code&gt; to see what it does.&lt;/p&gt;

&lt;p&gt;Read file: src/app/app.component.ts&lt;br&gt;
Based on the content of &lt;code&gt;src/app/app.component.ts&lt;/code&gt;, the &lt;code&gt;AppComponent&lt;/code&gt; does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Serves as the Root Component:&lt;/strong&gt; It's the main component bootstrapped for the application (indicated by the &lt;code&gt;selector: 'app-root'&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Provides the Main Template:&lt;/strong&gt; It uses &lt;code&gt;app.component.html&lt;/code&gt; as its template, which likely contains the main structure of your application's UI, including navigation and a &lt;code&gt;&amp;lt;router-outlet&amp;gt;&lt;/code&gt; where other components are displayed based on the current route.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Imports Necessary Modules/Components:&lt;/strong&gt; It imports &lt;code&gt;RouterOutlet&lt;/code&gt;, &lt;code&gt;RouterLink&lt;/code&gt;, &lt;code&gt;RouterLinkActive&lt;/code&gt; for routing, and &lt;code&gt;CommonModule&lt;/code&gt; for common Angular directives.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Injects Services and Store:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  It injects the NgRx &lt;code&gt;Store&lt;/code&gt; to select data.&lt;/li&gt;
&lt;li&gt;  It injects the &lt;code&gt;AuthService&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Selects State:&lt;/strong&gt; It selects the basket total (&lt;code&gt;total$&lt;/code&gt;) and basket item count (&lt;code&gt;count$&lt;/code&gt;) from the NgRx store using selectors. These are observables that will likely be used in the template (&lt;code&gt;app.component.html&lt;/code&gt;) to display the current basket status.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Provides Logout Functionality:&lt;/strong&gt; It has a &lt;code&gt;logout()&lt;/code&gt; method that calls the &lt;code&gt;logout&lt;/code&gt; method of the injected &lt;code&gt;AuthService&lt;/code&gt;. This method is likely called from a logout button in the template.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, inject } from '@angular/core';
import { RouterOutlet, RouterLink, RouterLinkActive } from '@angular/router';
import { Store } from '@ngrx/store';
import { selectBasketCount, selectBasketTotal } from './core/store/selectors/basket.selectors';
import { CommonModule } from '@angular/common';
import { AuthService } from './core/services/auth.service';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, RouterLink, RouterLinkActive, CommonModule],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss'
})
export class AppComponent {
    title = 'NGRX';
    store = inject(Store);
    total$ = this.store.select(selectBasketTotal);
    count$ = this.store.select(selectBasketCount);

    authService = inject(AuthService);

    logout() {
        this.authService.logout();
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  app.component.html
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;nav class="navbar navbar-expand-lg bg-body-tertiary"&amp;gt;
  &amp;lt;div class="container-fluid"&amp;gt;
    &amp;lt;a class="navbar-brand" routerLink="/"&amp;gt;{{ title }}&amp;lt;/a&amp;gt;
    &amp;lt;button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"&amp;gt;
      &amp;lt;span class="navbar-toggler-icon"&amp;gt;&amp;lt;/span&amp;gt;
    &amp;lt;/button&amp;gt;
    &amp;lt;div class="collapse navbar-collapse" id="navbarNav"&amp;gt;
      &amp;lt;ul class="navbar-nav"&amp;gt;
        &amp;lt;li class="nav-item"&amp;gt;
          &amp;lt;a class="nav-link" routerLink="/admin/stock" routerLinkActive="active" ariaCurrentWhenActive="page"&amp;gt;Stocks&amp;lt;/a&amp;gt;
        &amp;lt;/li&amp;gt;
        &amp;lt;li class="nav-item"&amp;gt;
          &amp;lt;a class="nav-link" routerLink="/admin/basket" routerLinkActive="active" ariaCurrentWhenActive="page"&amp;gt;Basket&amp;lt;/a&amp;gt;
        &amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/nav&amp;gt;

&amp;lt;main class="container mt-4"&amp;gt;
    &amp;lt;div class="row"&amp;gt;
        @if(authService.isAuthenticated() | async) {
            &amp;lt;button class="btn btn-danger col-1" (click)="logout()"&amp;gt;Logout&amp;lt;/button&amp;gt;
            &amp;lt;div class="col-3 offset-9 section-height"&amp;gt;
                &amp;lt;h5 class="card-title"&amp;gt;Basket&amp;lt;/h5&amp;gt;
                &amp;lt;span class="card-text"&amp;gt;{{ count$ | async }} for {{ total$ | async }} €&amp;lt;/span&amp;gt;
                &amp;lt;button class="btn btn-primary "  style="margin-left: 30px;" routerLink="/basket"&amp;gt;Go&amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;
        }
    &amp;lt;/div&amp;gt;



  &amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;
&amp;lt;/main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Connection
&lt;/h3&gt;

&lt;p&gt;We have to login.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Class &lt;code&gt;HomeComponent&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
    *   &lt;strong&gt;Dependency Injection:&lt;/strong&gt;&lt;br&gt;
        *   &lt;code&gt;authService = inject(AuthService);&lt;/code&gt;: Injects an instance of the &lt;code&gt;AuthService&lt;/code&gt;.&lt;br&gt;
        *   &lt;code&gt;router = inject(Router);&lt;/code&gt;: Injects an instance of the &lt;code&gt;Router&lt;/code&gt;.&lt;br&gt;
    *   &lt;strong&gt;Login Form Definition:&lt;/strong&gt;&lt;br&gt;
        *   &lt;code&gt;loginForm = new FormGroup(...)&lt;/code&gt;: Creates a new reactive form group named &lt;code&gt;loginForm&lt;/code&gt;.&lt;br&gt;
        *   It has two &lt;code&gt;FormControl&lt;/code&gt; instances:&lt;br&gt;
            *   &lt;code&gt;username: new FormControl('')&lt;/code&gt;: For the username input, initialized as an empty string.&lt;br&gt;
            *   &lt;code&gt;password: new FormControl('')&lt;/code&gt;: For the password input, initialized as an empty string.&lt;br&gt;
            This form will be bound to input fields in &lt;code&gt;home.component.html&lt;/code&gt;.&lt;br&gt;
    *   &lt;strong&gt;&lt;code&gt;login()&lt;/code&gt; Method:&lt;/strong&gt;&lt;br&gt;
        *   This method is likely called when the user submits the login form.&lt;br&gt;
        *   &lt;code&gt;console.log(this.loginForm.value);&lt;/code&gt;: Logs the current values from the form (username and password).&lt;br&gt;
        *   &lt;code&gt;this.authService.login(this.loginForm.value as UserAuth).subscribe(...)&lt;/code&gt;:&lt;br&gt;
            *   Calls the &lt;code&gt;login&lt;/code&gt; method of the &lt;code&gt;AuthService&lt;/code&gt;, passing the form values (cast to the &lt;code&gt;UserAuth&lt;/code&gt; type).&lt;br&gt;
            *   Subscribes to the &lt;code&gt;Observable&lt;/code&gt; returned by &lt;code&gt;authService.login()&lt;/code&gt; to handle the outcome:&lt;br&gt;
                *   &lt;code&gt;next: (token) =&amp;gt; {...}&lt;/code&gt;: If the login is successful (the observable emits a &lt;code&gt;true&lt;/code&gt; value, which is named &lt;code&gt;token&lt;/code&gt; here, though it's actually a boolean from &lt;code&gt;AuthService&lt;/code&gt;), it logs a success message and then navigates the user to the &lt;code&gt;/admin/stock&lt;/code&gt; route using &lt;code&gt;this.router.navigate(['/admin/stock']);&lt;/code&gt;.&lt;br&gt;
                *   &lt;code&gt;error: (error) =&amp;gt; {...}&lt;/code&gt;: If an error occurs during the login attempt (e.g., the observable errors out, or if &lt;code&gt;AuthService.login&lt;/code&gt; was designed to throw an error on failure, though currently it returns &lt;code&gt;of(false)&lt;/code&gt;), it logs an error message.&lt;/p&gt;

&lt;p&gt;In essence, the &lt;code&gt;HomeComponent&lt;/code&gt; provides a user interface (defined in &lt;code&gt;home.component.html&lt;/code&gt;) for users to enter their username and password, and then uses the &lt;code&gt;AuthService&lt;/code&gt; to attempt to log them in. If successful, it redirects them to an admin section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component, inject } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { AuthService } from '../core/services/auth.service';
import { UserAuth } from '../core/types';
import { Router } from '@angular/router';

@Component({
  selector: 'app-home',
  imports: [ReactiveFormsModule],
  templateUrl: './home.component.html',
  styles: ``
})
export class HomeComponent {
    authService = inject(AuthService);
    router = inject(Router);

    loginForm = new FormGroup({
        username: new FormControl(''),
        password: new FormControl(''),
    });

    login() {
        console.log(this.loginForm.value);
        this.authService.login(this.loginForm.value as UserAuth).subscribe({
            next: (token) =&amp;gt; {
                console.log('Login successful, redirecting to admin/stock', token);
                this.router.navigate(['/admin/stock']);
            },
            error: (error) =&amp;gt; {
                console.error('Login failed', error);
            }
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Storage in local
&lt;/h3&gt;

&lt;p&gt;With NGRX, you can store any kind of data in the browser.&lt;br&gt;
The problem is that when the page is refreshed, some data might be lost — and that’s something you don’t want to happen, especially when it comes to login credentials or the token used to determine whether the user is connected or not.&lt;/p&gt;

&lt;p&gt;We could store the data directly in localStorage, but the problem with that is we’d end up with two sources of truth: one from localStorage and another from NGRX, which can lead to confusion.&lt;br&gt;
To avoid this, we’ll store everything in NGRX and only persist a portion of it to localStorage.&lt;br&gt;
When accessing data, we’ll always go through NGRX, so we maintain a single source of truth.&lt;/p&gt;

&lt;p&gt;Let's first put the part that concerns us into localStorage.&lt;br&gt;
To do that, we first store it in NGRX.&lt;/p&gt;
&lt;h4&gt;
  
  
  auth.reducer
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;initialAuthState&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;export const initialAuthState: AuthState = { user: null, isAuthenticated: false, };&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  This defines the starting state for the authentication part of your application. When the application first loads, the &lt;code&gt;user&lt;/code&gt; will be &lt;code&gt;null&lt;/code&gt;, and &lt;code&gt;isAuthenticated&lt;/code&gt; will be &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;authReducer&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;export const authReducer = createReducer(...)&lt;/code&gt;: This is the main reducer function for authentication.&lt;/li&gt;
&lt;li&gt;  It's created using &lt;code&gt;createReducer&lt;/code&gt;, which takes the &lt;code&gt;initialAuthState&lt;/code&gt; as its first argument.&lt;/li&gt;
&lt;li&gt;  The subsequent arguments are &lt;code&gt;on(...)&lt;/code&gt; functions, which define how the state should change in response to specific actions:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;on(AuthActions.login, (state, { user }) =&amp;gt; ...)&lt;/code&gt;:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  This handles the &lt;code&gt;AuthActions.login&lt;/code&gt; action.&lt;/li&gt;
&lt;li&gt;  When a &lt;code&gt;login&lt;/code&gt; action is dispatched (carrying a &lt;code&gt;user&lt;/code&gt; payload), this function is executed.&lt;/li&gt;
&lt;li&gt;  It uses &lt;code&gt;produce(state, (draft: AuthState) =&amp;gt; { ... })&lt;/code&gt; from Immer.&lt;/li&gt;
&lt;li&gt;  Inside the Immer &lt;code&gt;produce&lt;/code&gt; function:

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;draft.user = user;&lt;/code&gt;: The &lt;code&gt;user&lt;/code&gt; property of the draft state is set to the &lt;code&gt;user&lt;/code&gt; payload from the action.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;draft.isAuthenticated = true;&lt;/code&gt;: The &lt;code&gt;isAuthenticated&lt;/code&gt; property is set to &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;  Immer ensures that a new, immutable state object is returned with these changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;on(AuthActions.logout, (state) =&amp;gt; ...)&lt;/code&gt;:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  This handles the &lt;code&gt;AuthActions.logout&lt;/code&gt; action.&lt;/li&gt;
&lt;li&gt;  When a &lt;code&gt;logout&lt;/code&gt; action is dispatched:&lt;/li&gt;
&lt;li&gt;  It uses &lt;code&gt;produce(state, (draft: AuthState) =&amp;gt; { ... })&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  Inside the Immer &lt;code&gt;produce&lt;/code&gt; function:

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;draft.user = null;&lt;/code&gt;: The &lt;code&gt;user&lt;/code&gt; property is set back to &lt;code&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;draft.isAuthenticated = false;&lt;/code&gt;: The &lt;code&gt;isAuthenticated&lt;/code&gt; property is set back to &lt;code&gt;false&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const initialAuthState: AuthState = {
    user: null,
    isAuthenticated: false,
};

export const authReducer = createReducer(
    initialAuthState,
    on(AuthActions.login, (state, { user }) =&amp;gt; produce(state, (draft: AuthState) =&amp;gt; {
        draft.user = user;
        draft.isAuthenticated = true;
    })),
    on(AuthActions.logout, (state) =&amp;gt; produce(state, (draft: AuthState) =&amp;gt; {
        draft.user = null;
        draft.isAuthenticated = false;
    }))
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;let make selector&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const selectAuthFeatureState = createFeatureSelector&amp;lt;AppState, AuthState&amp;gt;('authState');
export const selectAuthState = createSelector(
    selectAuthFeatureState,
    (state: AuthState) =&amp;gt; state
);
export const selectIsAuthenticated = createSelector(
    selectAuthState,
    (state: AuthState) =&amp;gt; state.isAuthenticated
);
export const selectUserCredentials = createSelector(
    selectAuthState,
    (state: AuthState) =&amp;gt; state.user
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally the actions for authentication trigger&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const AuthActions = createActionGroup({
    source: 'Auth',
    events: {
        login: props&amp;lt;{ user: UserAuth | null }&amp;gt;(),
        logout: emptyProps,
    },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember, we have a more global store, and authentication is just one part of it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
export * from './product.reducer';
export * from './basket.reducer';
export * from './reducers.type';
export * from './localstorage-custom.reducers';


export const reducers: ActionReducerMap&amp;lt;AppState&amp;gt; = {
    productsState: productsReducer,
    basketState: basketReducer,
    authState: authReducer, // authentication state to store also in local storage for persistance after refresh
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we’ll take that same part — and only that part — and store it in localStorage.&lt;br&gt;
To do this, we need to create a file that reads the data from localStorage and loads it into NGRX, and that also does the reverse each time the store is updated.&lt;br&gt;
file: localstorage-custom.reducer.ts&lt;/p&gt;

&lt;p&gt;This specific &lt;code&gt;localstorageCustomReducer&lt;/code&gt; is designed to &lt;strong&gt;synchronize a part of your NgRx store state with the browser's &lt;code&gt;localStorage&lt;/code&gt;&lt;/strong&gt;. This is a common pattern for persisting certain state, like authentication status, so that it can be restored when the user revisits the application.&lt;/p&gt;

&lt;p&gt;Here's a breakdown of its logic:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;localstorageCustomReducer&lt;/code&gt; Function:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  It takes one argument: &lt;code&gt;reducer: ActionReducer&amp;lt;any&amp;gt;&lt;/code&gt;, which is the next reducer in the chain (this could be your combined root reducer or another meta-reducer).&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;let isBrowser = typeof localStorage !== 'undefined';&lt;/code&gt;: Checks if the code is running in a browser environment where &lt;code&gt;localStorage&lt;/code&gt; is available. This is important because Angular applications can also be rendered on the server (Server-Side Rendering - SSR), where &lt;code&gt;localStorage&lt;/code&gt; wouldn't exist.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Returned Reducer Function &lt;code&gt;(state: AppState, action: Action) =&amp;gt; {...}&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  This is the actual meta-reducer logic that will be executed for every dispatched action.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;State Hydration (Loading from &lt;code&gt;localStorage&lt;/code&gt;):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;if(isBrowser &amp;amp;&amp;amp; (action.type === INIT || action.type === UPDATE))&lt;/code&gt;: This condition checks if it's running in a browser AND if the action is the initial &lt;code&gt;INIT&lt;/code&gt; action (when the store is first set up) or an &lt;code&gt;UPDATE&lt;/code&gt; action.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;const storageValue = localStorage.getItem(localStorageKey);&lt;/code&gt;: Tries to retrieve data from &lt;code&gt;localStorage&lt;/code&gt; using the &lt;code&gt;localStorageKey&lt;/code&gt; (i.e., &lt;code&gt;'auth-ngrx'&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;if(storageValue)&lt;/code&gt;: If data is found in &lt;code&gt;localStorage&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;try ... catch&lt;/code&gt;: It attempts to &lt;code&gt;JSON.parse()&lt;/code&gt; the stored string back into an object.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;return { ...state, [localStorageKey]: parsedAuth };&lt;/code&gt;: If parsing is successful, it returns a &lt;em&gt;new state&lt;/em&gt; object. This new state is a merge of the current &lt;code&gt;state&lt;/code&gt; and the &lt;code&gt;parsedAuth&lt;/code&gt; data loaded from &lt;code&gt;localStorage&lt;/code&gt;. Critically, it seems to be trying to set the &lt;em&gt;entire &lt;code&gt;parsedAuth&lt;/code&gt; object&lt;/em&gt; directly onto a property named &lt;code&gt;'auth-ngrx'&lt;/code&gt; within the &lt;code&gt;AppState&lt;/code&gt;. This might be slightly different from how the &lt;code&gt;authState&lt;/code&gt; is structured within &lt;code&gt;AppState&lt;/code&gt; (which is &lt;code&gt;state.authState&lt;/code&gt;). &lt;strong&gt;This is a potential point of interest/bug, as &lt;code&gt;localStorageKey&lt;/code&gt; is 'auth-ngrx', but your state structure is &lt;code&gt;AppState.authState&lt;/code&gt;. It should probably be merging into &lt;code&gt;state.authState&lt;/code&gt;.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  If parsing fails (e.g., the data in &lt;code&gt;localStorage&lt;/code&gt; is corrupted), it logs an error and removes the invalid item from &lt;code&gt;localStorage&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Processing by Next Reducer:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;const newState = reducer(state, action);&lt;/code&gt;: The original action is passed to the &lt;code&gt;reducer&lt;/code&gt; that was provided to the meta-reducer (your normal application reducers). This computes the "next" state based on the action, &lt;em&gt;after&lt;/em&gt; potentially having loaded from &lt;code&gt;localStorage&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;State Persistence (Saving to &lt;code&gt;localStorage&lt;/code&gt;):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;if(isBrowser)&lt;/code&gt;: Checks if running in a browser.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;localStorage.setItem(localStorageKey, JSON.stringify(newState.authState));&lt;/code&gt;: After the regular reducers have processed the action and produced &lt;code&gt;newState&lt;/code&gt;, this line takes the &lt;code&gt;authState&lt;/code&gt; slice from the &lt;code&gt;newState&lt;/code&gt; and saves it to &lt;code&gt;localStorage&lt;/code&gt; by &lt;code&gt;JSON.stringify&lt;/code&gt;-ing it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;return newState;&lt;/code&gt;: The meta-reducer returns the &lt;code&gt;newState&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;In Summary:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;On Initialization (&lt;code&gt;INIT&lt;/code&gt; action):&lt;/strong&gt; The meta-reducer attempts to load the authentication state (or whatever is stored under the &lt;code&gt;localStorageKey&lt;/code&gt;) from &lt;code&gt;localStorage&lt;/code&gt; and merge it into the initial application state.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;On Every Action:&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt; First, it lets your regular reducers (passed into it) calculate the new state based on the dispatched action.&lt;/li&gt;
&lt;li&gt; Then, it takes the &lt;code&gt;authState&lt;/code&gt; slice from this newly calculated state and saves it to &lt;code&gt;localStorage&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Potential Issue to Note:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As highlighted, there's a slight mismatch in how the state is being read from and written to &lt;code&gt;localStorage&lt;/code&gt; in relation to the &lt;code&gt;AppState&lt;/code&gt; structure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Reading:&lt;/strong&gt; &lt;code&gt;return { ...state, [localStorageKey]: parsedAuth };&lt;/code&gt; where &lt;code&gt;localStorageKey&lt;/code&gt; is &lt;code&gt;'auth-ngrx'&lt;/code&gt;. This would create &lt;code&gt;state['auth-ngrx']&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Writing:&lt;/strong&gt; &lt;code&gt;localStorage.setItem(localStorageKey, JSON.stringify(newState.authState));&lt;/code&gt; This correctly saves the &lt;code&gt;authState&lt;/code&gt; slice.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const localstorageCustomReducer = (reducer: ActionReducer&amp;lt;any&amp;gt;): ActionReducer&amp;lt;any&amp;gt; =&amp;gt; {
    let isBrowser = typeof localStorage !== 'undefined';

    return (state: AppState, action: Action) =&amp;gt; {
        if(isBrowser &amp;amp;&amp;amp; (action.type === INIT || action.type === UPDATE)) {
            const storageValue = localStorage.getItem(localStorageKey);
            if(storageValue) {
                try {
          const parsedAuth = JSON.parse(storageValue);
          return {
            ...state,[localStorageKey]: parsedAuth
                    };
                } catch (error) {
                    console.error('Error parsing local storage value', error);
                    localStorage.removeItem(localStorageKey);
                }
            }
        }
        const newState = reducer(state, action);

        if(isBrowser) {
            localStorage.setItem(localStorageKey, JSON.stringify(newState.authState));
        }
        return newState;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This meta-reducer is a powerful tool for making parts of your NgRx state persistent across browser sessions.&lt;/p&gt;

&lt;p&gt;in app.config&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
export const appConfig: ApplicationConfig = {
  providers: [
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter(routes),
        provideClientHydration(withEventReplay()),
        // Linking the local storage custom reducer to the store
    provideStore(reducers, { metaReducers: [localstorageCustomReducer] }),
    provideEffects(productEffects),
    provideStoreDevtools({ maxAge: 25, logOnly: !isDevMode() })
  ]
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
