שינוי זיהוי רכיב Glimmer לא עובד - שינוי מאפיינים במערך @tracked

שלום לכולם!

אני נתקל בבעיה עם זיהוי שינויים ברכיב Glimmer וזקוק להכוונה. כאשר אני משנה מאפיינים באובייקטים בתוך מערך \@tracked\\, התבנית לא מרנדרת מחדש.

\\ההגדרה שלי:\\

```javascript

import Component from '@glimmer/component';

import { tracked } from '@glimmer/tracking';

import { fn } from '@ember/helper';

import { on } from '@ember/modifier';

import { action } from '@ember/object';



export default class CustomSidebarComponent extends Component {

  @tracked items = [

    {

      id: 'home',

      label: 'Home',

      expanded: false

    },

    {

      id: 'my-posts', 

      label: 'My Posts',

      expanded: false

    }

    // ... more items

  ];



  @action

  toggleExpanded(item) {

    item.expanded = !item.expanded; // שינוי זה לא מפעיל רינדור מחדש

    console.log('Toggled:', item.label, item.expanded); // נרשם כראוי

  }



  <template>
    <div id="custom-sidebar">
      <ul>
        {{#each this.items key="@index" as |item|}}
          <li class="menu-item {{if item.expanded 'expanded'}}" {{on "click" (fn this.toggleExpanded item)}}>
            {{item.label}} {{if item.expanded "(expanded)" ""}}
          </li>
        {{/each}}
      </ul>
    </div>
  </template>

}

```

\\הבעיה:\\

  1. ה-click handler פועל כראוי
  2. המאפיין \item.expanded\\ מתעדכן (אומת בקונסול)
  3. אך התבנית לא מרנדרת מחדש - אין שינויי קלאסים, אין שינויי טקסט

\\מה שניסיתי:\\

  1. \\הקצאה מחדש של המערך\\ - \this.items = [...this.items]\\ לאחר השינוי (לא עובד)
  2. \\Immer לעדכונים בלתי ניתנים לשינוי\\ - רציתי לנסות זאת אך לא מצליח לגרום לייבוא npm לעבוד בנושאי Discourse
  3. \\אסטרטגיות מפתח שונות\\ - \key="id"\\ במקום \key="@index"\\

\\שאלות:\\

\- האם שינוי מאפיינים באובייקטים בתוך מערכי \@tracked\\ אמור לעבוד ב-Glimmer?
\- האם אני צריך להפוך אובייקטים בודדים למעקב כלשהו?
\- האם יש דפוס מומלץ לתרחיש שימוש זה?
\- האם זה יכול להיות קשור להרצה בסביבת נושא Discourse?
\- האם יש מגבלות עם ייבוא npm בנושאי Discourse שמשפיעות על ספריות תגובתיות?

\\סביבה:\\

\- רכיב נושא Discourse
\- רכיבי Glimmer עם קבצי \.gjs\\
\- גרסת Discourse אחרונה - עודכנה היום

כל תובנה תתקבל בברכה רבה! האם יש משהו בסיסי שאני מפספס לגבי מערכת התגובתיות של Glimmer?

תודה!

2 לייקים

ובכן, זה מוזר. טריק השמת המערך בדרך כלל עובד.

חלופה שמצאתי היא לגרום לאובייקטים במערך להיות ממחלקה עם מאפיינים מעקב משלה. משהו כמו:

class CustomSidebarItem {
  @tracked expanded = false;
  constructor(id, label) {
    this.id = id;
    this.label = label;
  }
}

export default class CustomSidebarComponent extends Component {

  @tracked items = [
    new CustomSidebarItem('home', 'Home'),
    new CustomSidebarItem('my-posts', 'My Posts'),
    ...
  ];
  // שאר הקוד שלך
}

זה יכול להיות יותר מפורט מאשר יצירת הרבה אובייקטים פשוטים, אבל מצאתי שזה מקל על הרחבה והיגיון, במיוחד אם אתה צריך לעשות משהו כמו העברת הנתונים לרכיבים מקוננים.

4 לייקים

Hi Alteras,

Thank you for your suggestion !!! It did work as suggested by you approach and really made our day bit easy ::)** :grinning_face:

2 לייקים

I believe when you track an array like described in OP you’re tracking the array reference and not changes to the individual objects within the array

Another way to handle it is using trackedObject, we use this in a handful of places throughout Discourse

3 לייקים

תודה על תרומתך. יש לי עוד שאלות המשך:

האם שימוש בספרייה כמו immer יעבוד?
אם כן, כיצד עלי לכלול את immer ב-discourse?
ראיתי אזכורים של ‘להעתיק אותו לנכסים מ-node_modules’, אבל הייתי מעדיף אם הייתה דרך לעשות זאת דרך npm, או אפילו קישור CDN בתגית הכותרת.

You can use loadScript() to load JS, even if the URL provided is an external URL. Using external services like jsdelivr should work with this.

import loadScript from "discourse/lib/load-script";

...

loadScript(URL).then(() => {
   // your code
})

Though I haven’t tested it extensively, a dynamic import should also work.

async function load() {
  const {
    default: myDefault,
    foo,
    bar,
  } = await import(URL);
  // rest of code
}

I should note that it is probably safer to save the NPM files directly into your code instead of relying on an external CDN, depending on how critical the JS is. Similarly, you may need to do a bit of bundling and preprocessing before being able to use it in the browser.


As for whether Immer will work with discourse, I don’t know.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.