
Product
Introducing Reports: An Extensible Reporting Framework for Socket Data
Explore exportable charts for vulnerabilities, dependencies, and usage with Reports, Socket’s new extensible reporting framework.
ngx-zustand
Advanced tools
The Zustand adapter for angular.
with npm:
npm install ngx-zustand zustand
with yarn:
yarn add ngx-zustand zustand
Create a service that extends ZustandBaseService.
interface CounterState {
counter: number;
increment: () => void;
decrement: () => void;
}
@Injectable({
providedIn: 'root',
})
export class CounterService extends ZustandBaseService<CounterState> {
initStore() {
return (set) => ({
counter: 0,
increment: () => set((state) => ({ counter: state.counter + 1 })),
decrement: () => set((state) => ({ counter: state.counter - 1 })),
});
}
}
@Component({
selector: 'app-counter-page',
standalone: true,
imports: [CommonModule],
template: `
<div *ngIf="store$ | async as store">
<div>
count: {{ store.counter }}
<div>
<div><button (click)="store.increment()">+</button></div>
<div><button (click)="store.decrement()">-</button></div>
</div>
</div>
</div>
`,
styles: [],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CounterPageComponent {
private counterService = inject(CounterService);
store$ = this.counterService.useStore();
}
store$ = this.store.useStore();
foo$ = this.store.useStore((state) => state.foo);
bar$ = this.store.useStore((state) => state.bar);
fooAndBar$ = this.store.useStore((state) => ({
foo: state.foo,
bar: state.bar,
}));
Just call set when you're ready, zustand doesn't care if your actions are async or not.
export class TodosStore extends ZustandBaseService<TodosState> {
initStore() {
return (set) => ({
todos: [],
loadTodos: () => {
this.http.get<Todo[]>().subscribe((todos) => set({ todos }));
},
});
}
}
set allows fn-updates set(state => result), but you still have access to state outside of it through get.
export class TodosStore extends ZustandBaseService<TodosState> {
initStore() {
return (set, get) => ({
todos: [],
action: () => {
const todos = get().todos;
},
});
}
}
You can override createStore function in order to include the middlewares you need.
import { devtools } from 'zustand/middleware';
@Injectable({
providedIn: 'root',
})
export class CounterService extends ZustandBaseService<CounterState> {
initStore() {
return devtools<CounterState>((set) => ({
counter: 0,
increment: () => set((state) => ({ counter: state.counter + 1 })),
decrement: () => set((state) => ({ counter: state.counter - 1 })),
}));
}
}
import { createJSONStorage, persist } from 'zustand/middleware';
@Injectable({
providedIn: 'root',
})
export class CounterService extends ZustandBaseService<CounterState> {
initStore(): StateCreator<CounterState> {
return (set) => ({
counter: 0,
increment: () => set((state) => ({ counter: state.counter + 1 })),
decrement: () => set((state) => ({ counter: state.counter - 1 })),
});
}
override createStore() {
return createStore(
persist<CounterState>(this.initStore(), {
name: 'counterStore',
storage: createJSONStorage(() => sessionStorage),
})
);
}
}
You can functionally compose your store any way you like. Please check typescript guide to a better explanation of how to type middlewares.
// Log every time state is changed
const logMiddleware = (config) => (set, get, api) =>
config(
(...args) => {
console.log(' applying', args);
set(...args);
console.log(' new state', get());
},
get,
api
);
export class CounterService extends ZustandBaseService<CounterState> {
initStore() {
return logMiddleware((set) => ({
counter: 0,
increment: () => set((state) => ({ counter: state.counter + 1 })),
decrement: () => set((state) => ({ counter: state.counter - 1 })),
}));
}
}
FAQs
The [Zustand](https://github.com/pmndrs/zustand) adapter for angular.
The npm package ngx-zustand receives a total of 5 weekly downloads. As such, ngx-zustand popularity was classified as not popular.
We found that ngx-zustand demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Explore exportable charts for vulnerabilities, dependencies, and usage with Reports, Socket’s new extensible reporting framework.

Product
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.