I'm cleaning up my angular2 project and for many reasons, I've decided to start with a seed. This one.
This seed uses HMR but I don't fully understand what is the purpose of that.
At the beginning, I was thinking that HMR was about dynamical loading and replacing component while the web app is running.
But since I've put my eyes on the app.service.ts
, I've got lost. Here is the code of this service :
import { Injectable } from '@angular/core';
import { HmrState } from 'angular2-hmr';
@Injectable()
export class AppState {
// @HmrState() is used by HMR to track the state of any object during a hot module replacement
@HmrState() _state = { };
constructor() {
}
// already return a clone of the current state
get state() {
return this._state = this._clone(this._state);
}
// never allow mutation
set state(value) {
throw new Error('do not mutate the `.state` directly');
}
get(prop?: any) {
// use our state getter for the clone
const state = this.state;
return state[prop] || state;
}
set(prop: string, value: any) {
// internally mutate our state
return this._state[prop] = value;
}
_clone(object) {
// simple object clone
return JSON.parse(JSON.stringify( object ));
}
}
I was thinking that service simply provides a space to store some data. After all, this is just an example.
But this line did confuse me: @HmrState() _state = { };
. Is this service using HMR to manage data that we can manage with this.appState.set('value', value);
(this is from the HomeComponent) like a little Redux's store (without actions, dispatcher, blabla) ?
What is the purpose of the decorator @HmrState()
here ?
Thanks.
When I had a first look at angular2-hmr
I was surprised as well. I thought it is something like a hot swap, but it is not really one. At least from what I see when I use it.
It looks like it always reloads the application regardless of the changes type. However it can restore the state of the swapped objects. The intention of @HmrState()
is to restore the component's state when the application is reloaded.
Let's take a look at a small example. We have a form with an input which is bound (with ngModel
or formControl
) to some component's property:
@Component({
template: `
<input [(ngModel)]="inputValue" />
<button (click)="click()">Click me</button>
`
})
export class MyComponent {
public inputValue: string;
public click() {
console.log(this.inputValue);
}
}
We type in some value, e.g. 'test123' and click the button. It works.
Then suddenly we realise: the log description is missing. So we go to our code and add it:
@Component({
template: `
<input [(ngModel)]="inputValue" />
<button (click)="click()">Click me</button>
`
})
export class MyComponent {
inputValue: string;
public click() {
console.log('inputValue:', this.inputValue);
}
}
Then the component's code is changed, HMR replaces it and we realise that the inputValue
is lost.
To restore the value during the HMR process angular2-hmr
needs some information about the object state before it was wiped out. Here the @HmrState()
comes into play: it points out to the state that should be restored. In other words to make the first code snippet work with HMR the following should be done:
@Component({
template: `
<input [(ngModel)]="state.inputValue" />
<button (click)="click()">Click me</button>
`
})
export class MyComponent {
@HmrState() public state = {
inputValue: ''
}
public click() {
console.log(this.state.inputValue);
}
}
The state is now known to the HMR processor and it can use the state to restore our value. Now when we change the component code to:
@Component({
template: `
<input [(ngModel)]="state.inputValue" />
<button (click)="click()">Click me</button>
`
})
export class MyComponent {
@HmrState() public state = {
inputValue: ''
}
public click() {
console.log('inputValue:', this.state.inputValue);
}
}
it magically reloads our application and the inputValue's value is preserved.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With