@e-square/ark
v16.0.0-next.6
Published
An innovative state management library meticulously crafted for Angular.
Downloads
48
Readme
Ark
An innovative state management library meticulously crafted for Angular.
Installation
Use the package manager npm to install Ark.
npm install @e-square-io/ark@latest
State Management
What is state management? The definition of state management is the handling of the data (state) shared across components in an application.
State management is implemented by stores.
Store
A store is a centralized container where a chunk of the application state resides. Stores can be categorized into two kinds: component stores and global/feature stores. Further discussion will be about feature stores. Feature stores contain data directly related to the application’s or feature's business logic.
Global or feature stores aim to ensure that data can be shared and manipulated across the application predictably and efficiently.
The store in Ark is an injectable Angular service. Extension of the abstract class Ark used to create one. Additionally, the State type and the initial state object must be created. The resulting code will look like the following example.
export interface SessionState {
user?: User;
}
@Injectable({
providedIn: 'root',
})
export class SessionStore extends Ark<SessionState> {
readonly $user = this.select('user');
constructor() {
super({}, withStoreConfiguration({ name: 'Session Store' }));
}
}
Updating the Store
To update the store’s value method update
is used. As an argument a partial state object or a callback function that receives the current state and must return a partial state object supposed to be provided.
Besides updating the store’s value, the method update
triggers beforeUpdate
and afterUpdate
interceptors accordingly and the onBeforeUpdate
lifecycle hook.
this.sessionStore.update({ user: value });
or
this.sessionStore.update(state => ({ ...state, user: value }))
Getting data from the Store
The store value can be extracted in two ways. First is the instantaneous value that can be achieved with the method getValue
. Second, use the method select
that returns the computed signal of the store value. Method select
can be invoked without arguments, it returns the signal with the whole state object. Or it receives the state object key or projection function that modifies the value of the resulting signal.
$user = this.select('user'); // $user is a readonly signal containing the User object
Customization
Ark constructor receives besides the initial state functional arguments called ArkFeatures
. An Ark feature is an object consisting of the feature kind and an object with the feature implementation. Right now, two kinds of features are implemented: interceptors and configuration.
Interceptors
Interceptors are functions being run at specific moments. Right now, there are five types of interceptors are supported:
BeforeInitInterceptor
. Runs in the store constructor and can transform the initial value of the store.AfterInitInterceptor
. Runs in the store constructor after the initial state is set.BeforeUpdateInterceptor
. Runs at the beginning of theupdate
method and can transform the state update request.AfterUpdateInterceptor
. Runs at the end of the update process and does additional side actions when the store has been updated.AfterResetInterceptor
. Runs after the store was reset to its initial value.
Interceptors can perform a variety of implicit tasks like validations, logging, adding, or removing data during the store update process.
Write an interceptor
First, decide which moment the interceptor suppose to run. Depending on that, create the function of the appropriate type. Note the types and the number of arguments and return value.
const beforeInit: BeforeInitInterceptor<UpdateSelectState> = initialState => {
console.log('Before init', initialState);
initialState.x = '';
return initialState;
};
const afterInit: AfterInitInterceptor<UpdateSelectState> = initialState => console.log('After init', initialState);
const beforeUpdate: BeforeUpdateInterceptor<UpdateSelectState> = (currState, newState, store) => {
console.log('%cBefore Update #1.', 'color: lightgreen');
console.log('Curr state:', currState, 'new state:', newState, 'store', store);
return newState;
};
const afterUpdate: AfterUpdateInterceptor<UpdateSelectState> = state => console.log('Updated successfully', state);
Now, provide all your interceptor functions to the ArkInterceptors
object and supply it with the withInterceptors
function to super
in the store constructor. Multiple interceptors can intercept the same moment and multiple withInterceptors
functions can be used.
Add and remove interceptor at run-time
Every store has the property hooks
that contains the instance of the Hooks
class. The Hooks
class provides methods to add and remove interceptors at run-time.
Store Lifecycle
Ark introduces its lifecycle additionally to the standard Angular. Your application can use lifecycle hooks methods, similar to component lifecycle hooks, to tap into the store update events.
Responding to Store update events
Respond to update events in the lifecycle of the store by implementing one or more of the lifecycle hook interfaces. The hooks allow you to act on the store and the store value at the appropriate moment when the update occurs.
Each interface defines the prototype for a single hook method, whose name is the interface name. For example, the OnBeforeUpdate
interface has a hook method onBeforeUpdate
. If you implement this method in your store class, Ark calls it shortly after the update process will be initiated.
onBeforeUpdate(currentState: UpdateSelectState, newState: Partial<UpdateSelectState>): Partial<UpdateSelectState> {
console.log('onBeforeUpdate', 'curr', currentState, 'new', newState);
return newState;
}
onAfterUpdate(): void {
console.log('onAfterUpdate', this.getValue());
}
Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Support
If you encounter any problems or have any questions, please file an issue on our GitHub page.