YOSHINO日記

プログラミングに関すること

Ember.js入門2: computed propertiesとobserverで状態変化を監視する

とりあえずObjectをつくる

app/app.js

import Application from '@ember/application';
import Resolver from './resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';
import myObject from './myObject'

const App = Application.extend({
  modulePrefix: config.modulePrefix,
  podModulePrefix: config.podModulePrefix,
  Resolver
});

loadInitializers(App, config.modulePrefix);

myObject();
export default App

新しくファイルを作成してそこでObjectを作ります。 ref: Classes and Instances

インスタンスのプロパティを再定義 reopen: https://guides.emberjs.com/release/object-model/reopening-classes-and-instances/

オブジェクトのプロパティを再定義 reopenClass: https://emberjs.com/api/ember/2.15/classes/Ember.Object/methods/reopenClass?anchor=reopenClass

app/myObject.js

import EmberObject from '@ember/object';

export default function() {
  const Light = EmberObject.extend({
    init(){
      alert("Lightオブジェクトの初期化が行われています。");
    },
    isOn: false
  });

  Light.reopen({
    color: 'yellow'
  });

  Light.reopenClass({
    wattage: 80
  });

  const bulb = Light.create();

  console.log(bulb.get('color'))
  console.log(Light.wattage)
}

computed propertiesについて学ぶ

computed propertiesはクラス内で通常のプロパティと同様に以下のように定義できる。

アクセスすると、computed propertiesで定義された値はキャッシュされる。

もし、computed propertiesで定義された値に変更がある場合は再計算される。

ref: https://guides.emberjs.com/release/object-model/computed-properties/

import EmberObject from '@ember/object';

export default function() {
  const Light = EmberObject.extend({
    isOn: false,
    color: 'yellow',

    description: Ember.computed(
      'isOn',
      'color',
      function(){
        return 'The ' + this.get('color') + ' light is set to ' + this.get('isOn');
      }),

    fullDescription: Ember.computed(
      'description',
      'age',
      function(){
        return 'The ' + this.get('description') + ' and the age is ' + this.get('age');
      }),

    aliasDescription: Ember.computed.alias('fullDescription')
  });

  const bulb = Light.create({age: 22});
  console.log(bulb.get('aliasDescription'));
}

Observer:propertyの変化を監視する

import EmberObject from '@ember/object';

export default function() {
  const Light = EmberObject.extend({
    isOn: false,
    color: 'yellow',
    age: null,

    description: Ember.computed(
      'isOn',
      'color',
      function(){
        return 'The ' + this.get('color') + ' light is set to ' + this.get('isOn');
      }),

    fullDescription: Ember.computed(
      'description',
      'age',
      function(){
        return 'The ' + this.get('description') + ' and the age is ' + this.get('age');
      }),

    desc: Ember.computed.alias('description'),

    checkChanged: Ember.observer(
      'isOn',
      function(){
        console.log('isOn value changed!')
      }
    )
  });

  const bulb = Light.create({age: 22});
  console.log(bulb.get('desc'));
  bulb.set('isOn',true)
}

コンソルのlog

The yellow light is set to false
myObject.js:25 isOn value changed!

computed propertiesとは全然異なるものである。

computed propertiesにはできて、observerにはできないことで、違いが明らかになる。

  • set、getメソッドを持たない
  • 返り値をもたない

以上の理由から、observerを利用するよりもcomputed propertiesを使うべきケースのほうが多い。

observerは複数のpropertyの変化を監視することが可能である。

    checkChanged: Ember.observer(
      'isOn',
      'color',
      function(){
        console.log('isOn value changed!')
      }
    )

例えば以下のようなケースでは、

const bulb = Light.create({age: 22});
console.log(bulb.get('desc'));
bulb.set('isOn',true)
bulb.set('color',`red`)
console.log(bulb.get('desc'));

以下のような出力。

The yellow light is set to false
isOn value changed!
isOn value changed!
The red light is set to true

上の例では、observerが2回実行されていることがわかる。 一度しか実行したくない場合は以下のようにする。

※reopenを使ってメソッドを上書きしています。

  Light.reopen({
    checkIsOn: Ember.observer(
      'isOn',
      'color',
      function(){
        Ember.run.once(this, 'checkChanged');
      }
    ),
    checkChanged: Ember.observer(
      'description',
      function(){
        console.log(this.get('description'));
      }
    )
  });
const bulb = Light.create({age: 22});
bulb.set('isOn',true)
bulb.set('color',`red`)

以下のようなログ出力

The red light is set to true