중첩 구조 추적 문제

topic-above-footer-buttons에 Glimmer 컴포넌트를 삽입하고 있습니다. 이 Glimmer 컴포넌트는 주제에 대한 일부 메타데이터를 표시하려고 합니다. 이 메타데이터를 topic.my_metadata에 직렬화하고 있습니다.

메타데이터가 백그라운드 작업(!)에서 업데이트되면, 주제는 MessageBus.publish("/topic/#{topic.id}", { reload_topic: true, refresh_stream: true })를 통해 새로고침됩니다.

이 경우 템플릿에서는 올바르게 업데이트됩니다:

{{this.args.topic.my_metadata.status}}

그러나 getter를 통해 접근할 때

get statusMessage() {
  return this.args.topic.my_metadata.status;
}

그렇다면

{{ this.statusMessage }}

는 업데이트되지 않습니다.

(그리고 this.args.topic.my_metadata에 어떤 방식으로든 의존하는 제가 가진 모든 getter도 마찬가지입니다. 이것이 실제 문제입니다.)

무엇을 잘못하고 있는 걸까요?

이미 많은 시도를 했습니다. 커스텀 이벤트 정의, topic.my_metadata를 @tracked metadata로 복사한 후 this.metadata를 사용하는 것 등등요.

어떤 값이 추적(tracked)되고(그 값이 변경되면) 그 값에 의존하는 getter가 재평가된다는 것만 보장된다고 생각합니다.

따라서 이 경우 {{this.args.topic.my_metadata.status}}가 더 나은 것 같지만, 참고로 이렇게 작성하는 것이 좋습니다: {{@topic.my_metadata.status}}

음, 이건 단순히 “더 좋다” 또는 "더 나쁘다"의 문제가 아닙니다. 메타데이터를 평가하고, 예를 들어 버튼이 표시되어야 하는지 여부를 결정하는 로직이 자바스크립트에 꽤 많이 존재하기 때문이죠. 예를 들어 다음과 같은 경우처럼요.

get showButton() {
   // this.args.topic.my_metadata.foo와 this.args.topic.my_metadata.bar에 대해 무거운 작업을 수행
}

따라서 저는 게터(getter)가 필수적이고, 그것들이 어떤 방식으로든 재평가되도록 해야 합니다.

게다가 Glimmer 문서에는 args와 그 값들이 자동으로 추적(autotrack)된다고 명시되어 있습니다.

템플릿이 그것들을 자동으로 추적할 수 있다면, 왜 게터는 그렇게 할 수 없을까요?

아래와 같이 메타데이터를 인자로 전달하는 경우에도 동작합니다:

{{this.getStatus this.args.topic.my_metadata}}

그리고 다음과 같은 함수와 함께요:

  getStatus(arg) {
    return arg.status;
  }

Ember의 ‘classic’ 반응성 시스템(get/set/computed)에서 ‘octane’ @tracked / 네이티브 게터로 전환하는 중간 단계에 있기 때문에 발생하는 불행한 부분입니다.

위에서 논의한 대로, 예제의 문제는 네이티브 게터에서 @tracked가 아닌 프로퍼티에 접근하고 있다는 것입니다.

템플릿에서 전체 경로를 직접 접근하면 작동하지만, 말씀하신 대로 사용할 수 있는 로직이 제한됩니다.

또는 .get()을 사용하면 Ember의 새로운 자동 추적(autotracking) 시스템이 classic(즉, @tracked가 아닌) 프로퍼티에 대해 작동할 수 있습니다.

따라서 이 경우 다음과 같이 작성하면 됩니다.

get statusMessage() {
  return this.args.topic.get("my_metadata.status");
}

데이비드, 감사합니다.

이것도 @computed로 해결할 수 있을까요, 아니면 안 되는 건가요?

  @computed('args.topic.my_metadata.status')
  get statusMessage() {
    // 이 부분은 훨씬 복잡할 수 있습니다
    return this.args.topic.my_metadata.status;
  }

계산이 중요한 경우 결과를 캐싱할 수 있다는 장점이 있다고 생각합니다.

(이 예시에서는 당연히 사소한 부분이지만, @RGJ가 언급했던 내용입니다)

@computed는 Ember의 클래식 반응성 시스템의 일부입니다. 공식적으로 비추천(deprecated)된 것은 아니지만, 새 코드에 추가하는 것을 피하도록 노력하고 있습니다.

게터가 캐싱이 필요할 정도로 복잡한 경우, @cached를 사용할 수 있습니다:

import { cached } from "@glimmer/tracking";

...

@cached
get statusMessage() {
  // 이 부분은 훨씬 더 복잡할 수 있습니다
  return this.args.topic.my_metadata.status;
}

정말 완벽하게 작동합니다. 금요일의 남은 시간을 구해 주셔서 감사합니다 @david !!! 정말 감사합니다!!