Skip to main content

Local Component State

We can manage a local component state using Akita and Angular. When we provide a store in the component's providers, it enables us to get a new store instance for each component we create.

For example:

counter.state.ts
import { guid, Store, StoreConfig } from '@datorama/akita';

type State = { counter: number };

@Injectable()
class CounterStore extends Store<State> {
constructor() {
super({ counter: 0 }, { name: `Counter-${guid()}` })
}
}

@Injectable()
class CounterQuery extends Query<State> {
constructor(protected store: CounterStore) { super(store); }
}
counter.component.ts
@Component({
selector: 'counter',
template: `
{{ counter$ | async }}
<button (click)="increment()">Increment</button>
`,
providers: [CounterStore, CounterQuery]
})
export class CounterComponent {
counter$ = this.query.select('counter');
@Output() update = this.counter$.pipe(skip(1));

constructor(
private store: CounterStore,
private query: CounterQuery
) { }

increment() {
this.store.update(({ counter }) => ({ counter: counter + 1 }));
}
}

Counter State Provider

You can also take a different approach and create a counter state provider:

counter.state
type State = { counter: number };

class CounterState {
store: Store<State>;
query: Query<State>;
}

function counterStateFactory(element: ElementRef<Element>) {
const name = element.nativeElement.getAttribute('name');
const store = new Store<State>({ counter: 0 }, { name });
const query = new Query<State>(store);

return {
store,
query
}
}
counter.component.ts
@Component({
selector: 'counter',
template: `
{{ counter$ | async }}
<button (click)="increment()">Increment</button>
`,
providers: [{
provide: CounterState,
useFactory: counterStateFactory,
deps: [ElementRef]
}]
})
export class CounterComponent {
counter$ = this.state.query.select('counter');
@Output() update = this.counter$.pipe(skip(1));

constructor(
private state: CounterState
) { }

increment() {
this.state.store.update(({ counter }) => ({ counter: counter + 1 }));
}
}

Open the Redux devtools, and you'll see the magic. You can play with the code here.

app.component.html
<counter (update)="onUpdate($event)" name="one"></counter>
<counter (update)="onUpdate($event)" name="two"></counter>
<counter (update)="onUpdate($event)" name="three"></counter>

Dynamic Stores

You can also manage a collection of stores in a service. For example:

@Injectable({ providedIn: 'root })
export class CountersService {
private stores = new Map();

createState(name: string) {
const store = new Store({ counter: 0 }, { name });
const query = new Query(store);

const state = { store, query };
this.stores.set(name, state);

return state
}

getState(name: string) {
return this.stores.get(name);
}
}