추적 중인 두 변수가 업데이트되지 않음

다음과 같은 코드가 있습니다:

import Component from "@glimmer/component";
import { apiInitializer } from "discourse/lib/api";
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { inject as service } from "@ember/service";
import { defaultHomepage } from "discourse/lib/utilities";


/*
const xhr = new XMLHttpRequest();
xhr.open("GET", "/cakeday/anniversaries/today.json");
xhr.send();
xhr.responseType = "json";
xhr.onload = () => {
    if (xhr.readyState == 4 && xhr.status == 200) {
        let resp = xhr.response;
        let numberOfAnns = resp['total_rows_anniversaires'];
        let allAnns = resp['anniversaries']; // 딕셔너리 목록입니다
        console.log(allAnns);
        let allAnnsUsernames = [];
        for (var annUserdata in allAnns) {
            console.log(allAnns[annUserdata]['username']);
            allAnnsUsernames.push(allAnns[annUserdata]['username']);
        }
        var annsOfData = {'num_anns': numberOfAnns, 'anns_users': allAnnsUsernames};
        
    }
};
return annsOfData;
*/


export default apiInitializer("1.14.0", (api) => {
    //const banner_location = settings.banner_location
    api.renderInOutlet(
        settings.banner_location,
        class BdaysAnnsBanner extends Component {
            @tracked annsDataFinal = null;
            @tracked bdaysDataFinal = null;
            @tracked areBothBannersVisible = true;
            @tracked isAnnsVisible = null;
            @tracked isBdaysVisible = null;

            @service router;

            constructor() {
                super(...arguments);
                this.fetchAnnsData(); // 초기화 시 자동으로 가져오기
                this.fetchBdaysData();
            }
        
            // 비동기로 데이터를 가져와서 추적 가능한 속성 업데이트
            @action
            async fetchAnnsData() {
                const response = await fetch("/cakeday/anniversaries/today.json");
                const json = await response.json();
        
                let numberOfAnns = parseInt(json['total_rows_anniversaries']);
                let allAnns = json['anniversaries']; // 딕셔너리 목록입니다
                let allAnnsUsernames = [];
        
                for (let annUserdata of allAnns) {
                    allAnnsUsernames.push(annUserdata['username']);
                }
        
                this.annsDataFinal = {'num_anns': numberOfAnns, 'anns_users': allAnnsUsernames, 'visible': true, 'isFilled': true};
                this.updateBothBannersVisibility(this.annsDataFinal);
            }

            // 비동기로 데이터를 가져와서 추적 가능한 속성 업데이트
            @action
            async fetchBdaysData() {
                 // 여기서 bdaysDataFinal 선언
                let bdaysDataFinal;
            
                // 생일 데이터 가져오기
                const response = await fetch("/cakeday/birthdays/today.json");
                const json = await response.json();
            
                // 데이터를 처리하는 로직 실행
                let numberOfBdays = parseInt(json['total_rows_birthdays']);
                let allBdays = json['birthdays']; // 딕셔너리 목록입니다
                let allBdaysUsernames = [];
            
                for (let bdayUserdata of allBdays) {
                    allBdaysUsernames.push(bdayUserdata['username']);
                }
            
                this.bdaysDataFinal = {'num_bdays': numberOfBdays, 'bdays_users': allBdaysUsernames, 'visible': true, 'isFilled': true};
                this.updateBothBannersVisibility(this.bdaysDataFinal);
                //console.log(annsDataFinal);  // 결과 확인용
            }


            @action
            updateBothBannersVisibility(bannerData) {
                console.log(bannerData.num_anns);
                // anns인지 bdays인지 확인
                if (bannerData.num_anns) { // anns인 경우
                    console.log('Anns:')
                    console.log(bannerData.num_anns);
                    if (bannerData.num_anns == 0 && settings.hide_unused_data) {
                        console.log(`Anns+setting: ${bannerData.num_anns == 0 && settings.hide_unused_data}`);
                        this.isAnnsVisible = false;
                        console.log(`isAnnsV: ${this.isAnnsVisible}`);
                        //console.log(this.isBdaysVisible);
                    }
                } else { // bdays인 경우  
                    console.log(bannerData.num_bdays);
                    if (bannerData.num_bdays == 0 && settings.hide_unused_data) {
                        console.log(`Bdays+setting: ${bannerData.num_bdays == 0 && settings.hide_unused_data}`);
                        this.isBdaysVisible = false;
                        console.log(`isBdaysV: ${this.isBdaysVisible}`);
                        //console.log(this.isAnnsVisible);
                    }
                }
                console.log(`isAnnsV: ${this.isAnnsVisible}`);
                console.log(`isBdaysV: ${this.isBdaysVisible}`);
                // 부등호를 사용합니다. 값이 같지 않으면(true) 배너가 표시되고, 같으면 부등호 조건이 충족되지 않아 배너가 숨겨집니다.
                this.areBothBannersVisible = !(this.isAnnsVisible === false && this.isBdaysVisible === false); // 또는: this.areBothBannersVisible = this.isAnnsVisible || this.isBdaysVisible;
                console.log(this.areBothBannersVisible);
            }

            
            // 데이터용 Getter
            get annsData() {
                //return this.annsDataFinal;
                if (this.annsDataFinal !== null) {
                    if (this.annsDataFinal.num_anns == 0) {
                        if (settings.hide_unused_data) {
                            this.annsDataFinal.isFilled = false;
                            this.annsDataFinal.visible = false;
                        } else {
                            this.annsDataFinal.isFilled = false;
                        }
                    } else {
                        this.annsDataFinal.isFilled = true;
                        this.annsDataFinal.visible = true;
                    }
                    
                    //this.updateBothBannersVisibility(this.annsDataFinal);
                    // 데이터가 아직 로드되지 않았다면 null 또는 기본값을 반환
                    return this.annsDataFinal;
                }
            }
        
            // 데이터용 Getter
            get bdaysData() {
                //return this.bdaysDataFinal;
                if (this.bdaysDataFinal !== null) {
                    if (this.bdaysDataFinal.num_bdays == 0) {
                        if (settings.hide_unused_data) {
                            this.bdaysDataFinal.isFilled = false;
                            this.bdaysDataFinal.visible = false;
                        } else {
                            this.bdaysDataFinal.isFilled = false;
                            this.bdaysDataFinal.visible = true;
                        }
    
                    } else {
                        this.bdaysDataFinal.isFilled = true;
                        this.bdaysDataFinal.visible = true;
                    }

                    //this.updateBothBannersVisibility(this.bdaysDataFinal);
                    // 데이터가 아직 로드되지 않았다면 null 또는 기본값을 반환
                    return this.bdaysDataFinal;
                }
            }

            get isHomepage() {
                const { currentRouteName } = this.router;
                return currentRouteName === `discovery.${defaultHomepage()}`;
            }
            //console.log(this.areBothBannersVisible);

            <template>
                {{#if this.areBothBannersVisible}}
                    {{#if this.isHomepage}}
                        <div class='bdaysannsbanner' id='bdaysannsbanner'>
                            {{#if this.annsData.visible}}
                                <div class='anns'>
                                    {{#if this.annsData.isFilled}}
                                        <p>{{this.annsData.num_anns}}명의 사용자가 결혼기념일을 축하하고 있습니다!</p>
                                        <!-- 결혼기념일 데이터 표시 -->
                                        {{#each this.annsData.anns_users as |username|}}
                                            <span><a class='mention'>{{username}}</a></span>
                                        {{/each}}
                                    {{else}}
                                        <p>오늘 결혼기념일인 사람은 없습니다!</p>
                                    {{/if}}
                                </div>
                            {{/if}}
                            <br />
                            {{#if this.bdaysData.visible}}
                                <div class='bdays'>
                                    {{#if this.bdaysData.isFilled}}
                                        <p>{{this.bdaysData.num_bdays}}명의 사용자가 생일을 축하하고 있습니다!</p>
                                        <!-- 생일 데이터 표시 -->
                                        {{#each this.bdaysData.bdays_users as |username|}}
                                            <span><a class='mention'>{{username}}</a></span>
                                        {{/each}}
                                    {{else}}
                                        <p>오늘 생일인 사람은 없습니다!</p>
                                    {{/if}}
                                </div>
                            {{/if}}
                        </div>
                    {{/if}}
                {{/if}}
            </template>
        }
    );
});

동작하지 않는 부분은 this.isAnnsVisible와 this.isBdaysVisible 변수입니다. 이 변수들이 업데이트되지 않는 것 같아서 배너가 계속 표시되고 있습니다.

이 변수들이 업데이트되지 않는다는 게 좀 이상합니다. 제대로 사용하고 있지 않은 걸까요?

이 문제를 다시 올리는 것이 죄송하지만, 왜 이런 일이 발생하는지 여전히 감이 잡히지 않습니다.
현재 제 코드:

import Component from "@glimmer/component";
import { apiInitializer } from "discourse/lib/api";
import { ajax } from "discourse/lib/ajax";
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { inject as service } from "@ember/service";
import { defaultHomepage } from "discourse/lib/utilities";
import { getOwner } from '@ember/application';


export default apiInitializer("1.14.0", (api) => {
    //const banner_location = settings.banner_location
    
    api.renderInOutlet(
        settings.banner_location,
        class BdaysAnnsBanner extends Component {
            @tracked annsDataFinal = null;
            @tracked bdaysDataFinal = null;
            @tracked areBothBannersVisible = true;
            @tracked isAnnsVisible = null;
            @tracked isBdaysVisible = null;

            @service router;

            constructor() {
                super(...arguments);
                this.fetchAnnsData(); // 초기화 시 자동으로 가져오기
                this.fetchBdaysData();
            }
        
            // 비동기로 데이터를 가져와서 추적 속성을 업데이트합니다
            @action
            async fetchAnnsData() {
                const response = await fetch("/cakeday/anniversaries/today.json");
                const json = await response.json();
                console.log(json);
                let numberOfAnns = parseInt(json['total_rows_anniversaries']);
                let allAnns = json['anniversaries']; // 딕셔너리 목록입니다
                let allAnnsUsernames = [];
        
                for (let annUserdata of allAnns) {
                    allAnnsUsernames.push(annUserdata['username']);
                }
        
                this.annsDataFinal = {'num_anns': numberOfAnns, 'anns_users': allAnnsUsernames, 'visible': true, 'isFilled': true};
                this.updateBothBannersVisibility(this.annsDataFinal);
            }

            // 비동기로 데이터를 가져와서 추적 속성을 업데이트합니다
            @action
            async fetchBdaysData() {
                 // 여기서 bdaysDataFinal 선언
                let bdaysDataFinal;
            
                // 생일 데이터 가져오기
                const response = await fetch("/cakeday/birthdays/today.json");
                const json = await response.json();
                
                // 데이터를 처리하는 로직 실행
                let numberOfBdays = parseInt(json['total_rows_birthdays']);
                let allBdays = json['birthdays']; // 딕셔너리 목록입니다
                let allBdaysUsernames = [];
            
                for (let bdayUserdata of allBdays) {
                    allBdaysUsernames.push(bdayUserdata['username']);
                }
            
                this.bdaysDataFinal = {'num_bdays': numberOfBdays, 'bdays_users': allBdaysUsernames, 'visible': true, 'isFilled': true};
                this.updateBothBannersVisibility(this.bdaysDataFinal);
                //console.log(annsDataFinal);  // 결과를 확인하기 위해
            }


            @action
            updateBothBannersVisibility(bannerData) {
                console.log(bannerData.num_anns);
                // anns인지 bdays인지 확인
                if (bannerData.num_anns) { // anns인 경우
                    console.log('Anns:');
                    console.log(bannerData.num_anns);
                    if (bannerData.num_anns == 0 && settings.hide_unused_data) {
                        console.log(`Anns+setting: ${bannerData.num_anns == 0 && settings.hide_unused_data}`);
                        this.isAnnsVisible = false;
                        console.log(`isAnnsV: ${this.isAnnsVisible}`);
                        //console.log(this.isBdaysVisible);
                    }
                } else { // bdays인 경우  
                    console.log(bannerData.num_bdays);
                    if (bannerData.num_bdays == 0 && settings.hide_unused_data) {
                        console.log(`Bdays+setting: ${bannerData.num_bdays == 0 && settings.hide_unused_data}`);
                        this.isBdaysVisible = false;
                        console.log(`isBdaysV: ${this.isBdaysVisible}`);
                        //console.log(this.isAnnsVisible);
                    }
                }
                console.log(`isAnnsV: ${this.isAnnsVisible}`);
                console.log(`isBdaysV: ${this.isBdaysVisible}`);
                // 부등호를 사용합니다. 같지 않으면 (true), 배너가 표시됩니다. 같으면 부등호가 만족되지 않아 배너가 숨겨집니다.
                this.areBothBannersVisible = !(this.isAnnsVisible === false && this.isBdaysVisible === false); // 또는: this.areBothBannersVisible = this.isAnnsVisible || this.isBdaysVisible;
                console.log(this.areBothBannersVisible);
            }

            
            // 데이터용 Getter
            get annsData() {
                //return this.annsDataFinal;
                if (this.annsDataFinal !== null) {
                    if (this.annsDataFinal.num_anns == 0) {
                        if (settings.hide_unused_data) {
                            this.annsDataFinal.isFilled = false;
                            this.annsDataFinal.visible = false;
                            this.isAnnsVisible = false;
                        } else {
                            this.annsDataFinal.isFilled = false;
                        }
                    } else {
                        this.annsDataFinal.isFilled = true;
                        this.annsDataFinal.visible = true;
                    }
                    
                    //this.updateBothBannersVisibility(this.annsDataFinal);
                    // 데이터가 아직 로드되지 않았다면 null 또는 기본값을 반환합니다
                    return this.annsDataFinal;
                }
            }
            
            // 데이터용 Getter
            get bdaysData() {
                //return this.bdaysDataFinal;
                if (this.bdaysDataFinal !== null) {
                    if (this.bdaysDataFinal.num_bdays == 0) {
                        if (settings.hide_unused_data) {
                            this.bdaysDataFinal.isFilled = false;
                            this.bdaysDataFinal.visible = false;
                            this.isBdaysVisible = false;
                            console.log(`this.isAnnsVisible: ${this.isAnnsVisible}`);
                            console.log(`this.isBdaysVisible: ${this.isBdaysVisible}`);
                        } else {
                            this.bdaysDataFinal.isFilled = false;
                            this.bdaysDataFinal.visible = true;
                        }
    
                    } else {
                        this.bdaysDataFinal.isFilled = true;
                        this.bdaysDataFinal.visible = true;
                    }

                    //this.updateBothBannersVisibility(this.bdaysDataFinal);
                    // 데이터가 아직 로드되지 않았다면 null 또는 기본값을 반환합니다
                    return this.bdaysDataFinal;
                }
            }

            get isHomepage() {
                const { currentRouteName } = this.router;
                return currentRouteName === `discovery.${defaultHomepage()}`;
            }
            //console.log(this.areBothBannersVisible);
            
            <template>
                {{#if this.areBothBannersVisible}}
                    {{#if this.isHomepage}}
                        <div class='bdaysannsbanner' id='bdaysannsbanner'>
                            {{#if this.annsData.visible}}
                                <div class='anns'>
                                    {{#if this.annsData.isFilled}}
                                        <p>{{this.annsData.num_anns}}명의 사용자가 결혼기념일을 축하하고 있습니다!</p>
                                        <!-- 결혼기념일 데이터 표시 -->
                                        {{#each this.annsData.anns_users as |username|}}
                                            <span><a class='mention'>{{username}}</a></span>
                                        {{/each}}
                                    {{else}}
                                        <p>오늘 결혼기념일인 사람이 없습니다!</p>
                                    {{/if}}
                                </div>
                            {{/if}}
                            <br />
                            {{#if this.bdaysData.visible}}
                                <div class='bdays'>
                                    {{#if this.bdaysData.isFilled}}
                                        <p>{{this.bdaysData.num_bdays}}명의 사용자가 생일을 축하하고 있습니다!</p>
                                        <!-- 생일 데이터 표시 -->
                                        {{#each this.bdaysData.bdays_users as |username|}}
                                            <span><a class='mention'>{{username}}</a></span>
                                        {{/each}}
                                    {{else}}
                                        <p>오늘 생일인 사람이 없습니다!</p>
                                    {{/if}}
                                </div>
                            {{/if}}
                        </div>
                    {{/if}}
                {{/if}}
            </template>
        }
    );
});

제 저장소:

아직 정확히 말하기는 어렵지만 …

이 await는 불필요합니다.

응답이 이미 객체여야 하므로 .json() 등이 왜 필요한지 모르겠네요. 아마 이것을 훨씬 간소화할 수 있을 것입니다.

추적되는 변수들이 컴포넌트 전체 범위 내에 있으므로 this를 전달할 필요가 없습니다. 그냥 함수를 호출하고 액션에서 해당 변수를 참조하세요.

스타일 팁:

  • 공유 코드에 console.log를 너무 많이 사용하지 마세요. 그러면 핵심을 파악하기 어려워집니다.
  • 디스코스(Discourse) 표준인 4칸이 아닌 2칸 들여쓰기를 사용하세요. 템플레이터를 참고하세요.
  • 이를 전용 .gjs 파일로 이동하는 것을 고려해 보세요.
  • 필요할 경우 GitHub에서 번호를 클릭하면 코드를 미리 볼 수 있는 공유 링크를 얻을 수 있습니다.

고급:

  • Prettier와 ESlint를 설정하세요 … 전자는 스타일, 후자는 스타일과 함께 몇 가지 버그를 발견하는 데 도움이 될 수 있습니다.

이게 아니죠?

그렇게까지 할 필요는 없지만, 선택지는 있습니다.

처음에는 수동으로 처리하면 충분합니다.

이런 방식은 작동하지 않을 가능성이 높습니다.

EmberJS가 중첩된 속성을 관찰하지 않는다고 생각합니다.

같은 레벨에서 속성을 생성하고 추적하며 테스트해야 합니다.

예를 들어 annsDataVisible이라는 추적(tracked) 속성을 생성하고, 그 값을 업데이트한 후 if 문에서 사용하세요.

자식 속성의 값만 변경하는 것이 다시 그리기를 트리거할 수 있으므로, 매번 값이 아닌 전체 객체를 다시 할당할 수도 있습니다.