私は最初にVue.jsを学び、今ではAngular 4にプロジェクトがあるので、Angularを学びました。すべてがVue 「計算プロパティ」:Vueでは、他のプロパティの変更をリッスンし、計算を自動的に実行する計算プロパティを作成できます。
例えば(in Vue 2):
computed: {
name(){
return this.firstname + ' ' + this.lastname;
}
}
Nameプロパティは、firstnameまたはlastnameのいずれかが変更された場合にのみ再計算されます。これをAngular 2または4で処理するには?
はい、できます。
TSファイル内:
export class MyComponent {
get name() {
return this.firstname + ' ' + this.lastname;
}
}
その後、htmlで:
<div>{{name}}</div>
以下に例を示します。
@Component({
selector: 'my-app',
template: `{{name}}`,
})
export class App {
i = 0;
firstN;
secondN;
constructor() {
setInterval(()=> {
this.firstN = this.i++;
this.secondN = this.i++;
}, 2000);
}
get name() {
return this.firstN + ' ' + this.secondN;
}
}
これはすでに答えられていますが、これはあまり良い答えではなく、ユーザーは角度で計算されたプロパティとしてゲッターを使用すべきではないと思います。なぜ尋ねるか? getterは関数の単なるシュガー構文であり、単純な関数にコンパイルされます。つまり、変更検出チェックのたびに実行されます。プロパティは変更時に何百回も再計算されるため、これはパフォーマンスにとってひどいものです。
この例を見てください: https://plnkr.co/edit/TQMQFb?p=preview
@Component({
selector: 'cities-page',
template: `
<label>Angular computed properties are bad</label>
<ng-select [items]="cities"
bindLabel="name"
bindValue="id"
placeholder="Select city"
[(ngModel)]="selectedCityId">
</ng-select>
<p *ngIf="hasSelectedCity">
Selected city ID: {{selectedCityId}}
</p>
<p><b>hasSelectedCity</b> is recomputed <b [ngStyle]="{'font-size': calls + 'px'}">{{calls}}</b> times</p>
`
})
export class CitiesPageComponent {
cities: NgOption[] = [
{id: 1, name: 'Vilnius'},
{id: 2, name: 'Kaunas'},
{id: 3, name: 'Pabradė'}
];
selectedCityId: any;
calls = 0;
get hasSelectedCity() {
console.log('hasSelectedCity is called', this.calls);
this.calls++;
return !!this.selectedCityId;
}
}
計算されたプロパティが本当に必要な場合は、mobxのような状態コンテナを使用できます
class TodoList {
@observable todos = [];
@computed get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length;
}
}
mobxには@computedデコレータがあるため、getterプロパティはキャッシュされ、必要な場合にのみ再計算されます
Andzej Maciusovic
が標準的な答えを取得することを望んでいるのを改善しようとします。実際、VueJSには計算されたプロパティと呼ばれる機能があり、例を使用してすばやく表示できます。
<template>
<div>
<p>A = <input type="number" v-model="a"/></p>
<p>B = <input type="number" v-model="b"/></p>
<p>C = <input type="number" v-model="c"/></p>
<p>Computed property result: {{ product }}</p>
<p>Function result: {{ productFunc() }}</p>
</div>
</template>
<script>
export default {
data () {
return {
a: 2,
b: 3,
c: 4
}
},
computed: {
product: function() {
console.log("Product called!");
return this.a * this.b;
}
},
methods: {
productFunc: function() {
console.log("ProductFunc called!");
return this.a * this.b;
}
}
}
</script>
ユーザーがa
またはb
の入力値を変更するたびに、product
とproductFunc
の両方がコンソールにログを記録します。ユーザーがc
を変更すると、productFunc
のみが呼び出されます。
Angularに戻ると、 mobxjs はこの問題に本当に役立ちます。
npm install --save mobx-angular mobx
を使用してインストールしますobservable
およびcomputed
属性を使用しますTSファイル
import { observable, computed } from 'mobx-angular';
@Component({
selector: 'home',
templateUrl: './home.component.html',
animations: [slideInDownAnimation]
})
export class HomeComponent extends GenericAnimationContainer {
@observable a: number = 2;
@observable b: number = 3;
@observable c: number = 4;
getAB = () => {
console.log("getAB called");
return this.a * this.b;
}
@computed get AB() {
console.log("AB called");
return this.a * this.b;
}
}
マークアップ
<div *mobxAutorun>
<p>A = <input type="number" [(ngModel)]="a" /> </p>
<p>B = <input type="number" [(ngModel)]="b" /> </p>
<p>C = <input type="number" [(ngModel)]="c" /> </p>
<p> A * B = {{ getAB() }}</p>
<p> A * B (get) = {{ AB }}</p>
</div>
a
またはb
が変更された場合、AB
が1回呼び出され、getAB
が数回呼び出されます。 c
が変更された場合、getAB
のみが呼び出されます。したがって、このソリューションは、計算を実行する必要がある場合でもより効率的です。
場合によっては、Pure Pipeを使用するのが合理的な代替策である可能性があります。明らかに、いくつかの制限がありますが、少なくともイベントで関数を実行するコストを回避します。
@Pipe({ name: 'join' })
export class JoinPipe implements PipeTransform {
transform(separator: string, ...strings: string[]) {
return strings.join(separator);
}
}
テンプレートでは、フルネームプロパティの代わりに、' ' | join:firstname:lastname
を使用することもできます。計算されたプロパティがまだ角度に対して存在しないことはかなり悲しいです。