طريقة أخرى لتتبع هياكل البيانات المتداخلة

لا يؤدي @tracked حالة مصفوفة أو كائن داخل مكون Glimmer إلى تشغيل التحديثات عند تغيير عضو في المصفوفة/الكائن.

يناقش هذا الموضوع بعض الخيارات لجعل عرضك يتحدث بشكل صحيح. أردت إضافة طريقة أخرى، حيث أن الخيارات التي نوقشت هناك لم تنجح معي.

كيف قمت بحل هذا: بدلاً من تعيين عنصر واحد في كل مرة، قم بتعيين المصفوفة بأكملها دفعة واحدة. ستعمل هذه الاستراتيجية نفسها مع كائن أو أي بنية بيانات أخرى.

في مكون Glimmer:

@tracked categories = [];

constructor() {
  super(...arguments);
  this.loadAllData();
}

async loadAllData() {
  const categories = []
  const waiting = this.siteSettings.county_fence_print_categories.split('|').map(async (cid, index) => {
    const data = await this.loadData(`/c/${cid}/l/latest.json?period=monthly`)
    return data.topic_list.topics
  })

  // هذا هو السطر الذي يجب ملاحظته
  // لأننا نستخدم = مباشرة على المصفوفة، فسيؤدي ذلك إلى تشغيل تحديث.
  // بينما الدفع إلى المصفوفة أو تعيين العناصر حسب الفهرس لن يؤدي إلى تشغيل تحديث.
  this.categories = await Promise.all(waiting)
}

async loadData(url) {
  try {
    const data = await ajax(url);
    //console.log(`Got data for ${url}:`, data)
    return data
  } catch (error) {
    console.error(`Failed to get data for ${url}:`, error);
  }
}

يمكنك القيام بذلك مع تحديث جزئي أيضًا. الشيء المهم هو أن يكتشف JavaScript أنه يتم تعيين قيمة مختلفة. لذا بينما سيعمل .concat، لأنه ينشئ مصفوفة جديدة تختلف عن القديمة:

this.categories = this.categories.concat(newValue)

من المحتمل أن .push لن يعمل، لأن المصفوفة الناتجة هي نفس معرف الكائن الأصلي، وبالتالي يعتقد JavaScript أنه لم يتغير شيء.

this.categories.push(newValue)
this.categories = this.categories

إذا كنت تعمل مع كائن، فإن الطريقة السهلة لإنشاء واحد جديد هي باستخدام Object.assign() - الذي ينشئ بنية بيانات جديدة وموسعة، مثل .concat أعلاه.

لقد كان هذا هو الحال لفترة طويلة مع أطر عمل أخرى مثل Vue.js أيضًا - يمكنك العثور على مواضيع حول هذا تعود إلى 10 سنوات. يتعلق الأمر بالطريقة التي يتم بها تنفيذه في JavaScript، ربما إما getters/setters على الكائن الأصلي أو واجهة برمجة تطبيقات observe. ولكن إذا تم تنفيذه باستخدام واجهة برمجة تطبيقات observe، فهناك سبب أقل قليلاً لهذا السلوك، حيث سيكون من السهل تبديل علامة subtree… ربما اختاروا عدم القيام بذلك لأسباب تتعلق بالأداء عند مراقبة بنية متداخلة بعمق؟ لكنني أبتعد عن الموضوع، هذه تفاصيل تنفيذ للمكتبات الأساسية. يجب أن تساعدك الحلول البديلة المذكورة أعلاه في التنقل خلال هذا.

إعجابَين (2)

أتساءل عما إذا كانت TrackedArray ستساعد هنا؟
لم أتعمق أكثر من ذلك. لقد تذكرت فقط أن كود Discourse يستخدم هذا هنا وهناك.

import { TrackedArray, TrackedObject } from "@ember-compat/tracked-built-ins";

إعجابَين (2)

تخيل لو تم توثيق ذلك. :ضحك:

ولكن نعم، يبدو أن هذا مصمم خصيصًا لهذا السيناريو.

إعجابَين (2)