@cached는 언제 EmberJS에서 다시 계산됩니까?

11137 단어 ember
사용자 상호 작용을 통해 업데이트되는 속성productName이 있다고 가정해 보겠습니다. 간단하게 작업을 간단한 버튼 클릭으로 만들어 제품 이름을 항상 bar로 업데이트합니다.

// template.hbs

<button 
  type="button" 
  {{on "click" (fn this.updateProductName 'bar')}}
>
  Update Product Name
</button>

<p>
  Product name is: {{this.productName}}
</p>

<p>
  Product details are: {{this.productDetails}}
</p>


모던EmberJS (Octane)에서는 productName 속성을 @tracked decorator 으로 표시해야 값이 변경되면 템플릿에서 업데이트됩니다.

// controller.js

import Controller from '@ember/controller';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';

export default class ApplicationController extends Controller {
  @tracked productName = 'foo';

  @action updateProductName(newValue) {
    console.log(
      `productName was '${this.productName}'`,
      `updating to '${newValue}'`
    );

    this.productName = newValue;
  }
}


이제 productDetails 값을 사용하고 계산 비용이 많이 드는 파생 속성 productName ( via native ES6 getter )을 만들고 싶다고 가정해 보겠습니다. 해당 속성은 아마도 캐시되어야 합니다. Ember에서 이를 수행하는 표준 방법은 @cached decorator 입니다.

// controller.js
import Controller from '@ember/controller';
import { action } from '@ember/object';
import { tracked, cached } from '@glimmer/tracking';

export default class ApplicationController extends Controller {
  @tracked productName = 'foo';

  @cached
  get productDetails() {
    console.log(
      `updating productDetails because`,
      `productName was updated to '${this.productName}'`
    );

    // .. Some expensive computation
    return `Expensive cache of ${this.productName}`;
  }

  @action updateProductName(newValue) {
    console.log(
      `productName was '${this.productName}'`,
      `updating to '${newValue}'`
    );

    this.productName = newValue;
  }
}


문제



이제 사용자가 버튼을 여러 번 클릭하면 어떻게 될까요?

나는 다소 순진하게도 "상세 정보 로그"가 한 번만 나타날 것으로 예상했습니다. 첫 번째 클릭 후 productNamefoo에서 bar로 업데이트했습니다. 두 번째 및 이후의 각 클릭은 barbar로 다시 덮어씁니다. 실제로 값을 변경하지 않습니다. 따라서 @tracked는 더티로 표시할 필요가 없으며 @cached를 다시 계산할 필요가 없습니다. 오른쪽?



잘못된. 결과적으로 @tracked는 자신의 이전 값이 무엇인지 상관하지 않습니다. 업데이트를 시도한 것만 중요합니다.

수정: Ben Demboskinoted on Discord:

@tracked properties get dirtied when you write to them, period


productDetails의 계산이 정말 비싸고 productName의 값이 변경되지 않으면 다시 실행되지 않도록 하고 싶다고 가정해 보겠습니다. 그렇게하는 방법?

해결책



수동



해결책은 값이 변경되지 않았을 때 업데이트하지 않는 것입니다productName.

  @action updateProductName(newValue) {
    if(this.productName !== newValue) {
      this.productName = newValue;
    }
  }


애드온 사용



커뮤니티의 모든 것과 마찬가지로 가려움증이 있으면 누군가 곧 스크래처를 다시 만들 것입니다. tracked-toolbox addon을 설치하면 다음 설명이 있는 @dedupeTracked 데코레이터를 얻게 됩니다.

Turns a field in a deduped @tracked property. If you set the field to the same value as it is currently, it will not notify a property change (thus, deduping property changes). Otherwise, it is exactly the same as @tracked.



따라서 코드는 다음으로만 변경하면 됩니다.

// controller.js

import { dedupeTracked } from 'tracked-toolbox';

...

@dedupeTracked productName = 'foo';

...


결론


  • 값이 현재 저장된 것과 동일하더라도 @tracked 속성에 쓸 때 더럽혀집니다.
  • 캐싱이 어렵습니다.



  • Pexels의 Andrea Piacquadio님의 사진

    좋은 웹페이지 즐겨찾기