Vue: [ميزة] القدرة على تعطيل مراقبة Vue

تم إنشاؤها على ٧ أبريل ٢٠١٦  ·  50تعليقات  ·  مصدر: vuejs/vue

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


لدينا بعض النماذج غير العادية حيث نحتاج إلى تعطيل مراقبة Vue والمشي. مثال على ذلك هو نموذج الموارد الذي لديه حق الوصول إلى ذاكرة التخزين المؤقت بحيث يمكنه البحث عن الموارد ذات الصلة. يؤدي هذا إلى مشاهدة جميع الكائنات الموجودة في ذاكرة التخزين المؤقت (ربما تكون غير فعالة) ، بالإضافة إلى بعض التفاعلات الإضافية مع التعليمات البرمجية الأخرى. حاليًا ، نتغلب على هذا من خلال تعيين مراقب وهمي في ذاكرة التخزين المؤقت. شيء مشابه لـ ...

import get from 'http';
import Resource from 'resource';


new Vue({
    data: { instance: {}, },
    ready() { this.fetch(); },

    methods: {
        fetch() {
            const Observer = Object.getPrototypeOf(this.instance.__ob__).constructor;

            get('/api/frobs')
            .then(function(data) {
                // initialize Resource w/ JSON document
                const resource = new Resource(data);

                // Protect cache with dummy observer
                resource.cache.__ob__ = new Observer({});

                this.instance = resource;
            });
        },
    },
});

هذا لا يعمل ، ولكن

  • يعتمد على مكونات vue الداخلية
  • يتطلب كائنًا تمت ملاحظته بالفعل نظرًا لأنه لا يمكننا استيراد فئة Observer مباشرة.

عرض:
أضف طريقة رسمية لتعطيل مراقبة / مشي Vue بشكل صريح. على سبيل المثال ، شيء مثل ...

const someThing = {
  nestedThing: {},
};

// make entire object non-reactive
Vue.nonreactive(someThing);

// make nested object non-reactive
Vue.nonreactive(someThing.nestedThing);
vm.$set('key.path', someThing);

الاعتبارات:

  • ماذا يجب أن يحدث إذا قام المستخدم بتعيين مسار مفتاح تفاعلي لكائن غير تفاعلي؟ هل يجب أن يحذر vue المستخدم؟ على سبيل المثال ،

شبيبة
vm. $ set ('a'، Vue.nonreactive ({})؛

// مختلف عن..
vm. $ set ('a'، {
someKey: Vue.nonreactive ({}) ،
}) ؛
""

  • هل يجب أن يحذر الكائن التفاعلي بالفعل المستخدم إذا حاول أن يكون غير تفاعلي؟ على سبيل المثال ،

شبيبة
// خطأ
Vue.nonreactive (vm. $ data.a)

// صالح
Vue.nonreactive (_. clone (vm. $ data.a)) ؛
""

التعليق الأكثر فائدة

  1. إذا كنت بحاجة إلى تخطي ملاحظة كائن / مصفوفة في data ، فاستخدم Object.freeze() عليها ؛
  2. لا تحتاج إلى وضع عنصر في data للوصول إليه على this . إذا قمت ببساطة بإرفاقه بـ this في الخطاف created() ، فلن يتم ملاحظته على الإطلاق.

ال 50 كومينتر

ألن يعمل Object.freeze() في حالتك؟ إنه مدعوم منذ الإصدار 1.0.18

  1. إذا كنت بحاجة إلى تخطي ملاحظة كائن / مصفوفة في data ، فاستخدم Object.freeze() عليها ؛
  2. لا تحتاج إلى وضع عنصر في data للوصول إليه على this . إذا قمت ببساطة بإرفاقه بـ this في الخطاف created() ، فلن يتم ملاحظته على الإطلاق.
  • Object.freeze لا يعمل هنا. يتم تحديث ذاكرة التخزين المؤقت بمرور الوقت.
  • المورد الرئيسي _ هو رد الفعل. أنا مهتم في الغالب بجعل كائن ذاكرة التخزين المؤقت المتداخلة غير تفاعلي.

ثم ربما حان الوقت لإعادة التفكير في تصميم النموذج الخاص بك. لماذا تعشش هذه الأشياء تحت شيء يجب ملاحظته؟

لأنه يتم استخدام ذاكرة التخزين المؤقت للبحث ديناميكيًا عن الموارد ذات الصلة.

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

استدعاء author.posts يحصل على المشاركات من ذاكرة التخزين المؤقت.

حسب التصميم ، لا يشجع Vue وضع الكائنات المعقدة بآلية تغيير الحالة الخاصة بها في مثيل Vue data . يجب أن تضع الحالة الصافية فقط مثل البيانات المرصودة في مثيلات Vue. يمكنك معالجة هذه الحالات بأي طريقة تريدها ، ولكن لا ينبغي أن تكون الكائنات المسؤولة عن مثل هذه التلاعبات جزءًا من حالة مثيل Vue.

أولا ، توضيح السؤال - ماذا تقصد بالضبط بالحالة النقية ؟ لدينا نوعان من الحالات:

  • حالة النموذج (دائمة ، البيانات متزامنة مع متجر. على سبيل المثال ، todo)
  • حالة vue (مؤقتة ، البيانات التي تتحكم في سلوك العرض. على سبيل المثال ، طي / إظهار قائمة المهام)

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

<!-- layout -->
<post :post="post"></post>
<author :author="author" ><author>
<comments :comments="comments"></comments>
import post from 'components/post';
import author from 'components/author';
import comments from 'components/comments';
/* post = {
 *     template: '...'
 *     props: ['post'],
 *     data: () => {collapsed: false},
 *     ...
 * };  */

new Vue({
    el: 'body',
    data() { 
        instance = postStore.fetch({include: ['author', 'comments.author']})
        Vue.nonreactive(instance.cache)

        return {post: instance, },
    },
    components: {
        post,
        author,
        comments,
    },
    ...
});

بشكل أساسي ، لدينا وجهة نظر رئيسية مسؤولة عن وضع المكونات القابلة لإعادة الاستخدام في تخطيط وجلب / ربط البيانات بالمكونات المرتبطة. لا تجلب المكونات الفرعية البيانات الخاصة بها لأن البيانات مختلفة في سياقات مختلفة. على سبيل المثال ، قائمة بتعليقات _ المستخدم_ في مقابل قائمة تعليقات _ المشاركة_.

النموذج "غبي" إلى حد ما باستثناء أن الكائنات ذات الصلة ليست متداخلة ( {post: {author: {}, comments: []}} ) ، ولكن بدلاً من ذلك يتم البحث عنها من ذاكرة التخزين المؤقت. على سبيل المثال ، قد يكون post.comments[2].author هو نفس الكائن مثل post.author . لذلك ، بدلاً من الحصول على نسخ متعددة من كائن المؤلف ، لدينا فقط نسخة تم البحث عنها من ذاكرة التخزين المؤقت. لا توجد أي طفرة في ما سبق - كل البيانات مصنوعة في الجلب الأولي.

أيضًا ، لم يعد الطلب ذا صلة بعد الآن ، ولكن قد يكون البديل هو عدم مراقبة أعضاء الكائن "الخاص". يمكن أن يكون هذا أعضاء بشرطة سفلية فردية رائدة أو ربما مزدوجة. الجانب السلبي لهذا النهج هو أنه سيكون كسر التغيير.

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

rpkilby شكرا للمشاركة!

rpkilby طريقة واحدة أقوم بنسخ كائن وإزالة الملحوظة / التفاعلية

var newObj = JSON.parse(JSON.stringify(obj))

مفيد حقًا لأنني أريد الاحتفاظ بمجموعة من "الحالات" وتنفيذ كائن تاريخ الحالة في vuex.

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

في الوقت الحالي ، لا يعد تجميد الكائن حلاً طويل المدى. [Vue-nonreactive] لها Vue باعتبارها تبعية وهي مبالغة عندما يتعلق الأمر بفعل شيء ما بشكل مباشر. ألا يكفي إجراء فحص بسيط في الكود مثل instance.__ob__ !== false ؟ سيسمح هذا للمكتبات بضمان عدم ملاحظة أشياء مثل ذاكرات التخزين المؤقت.

class Unobservable {
  construtor() {
    Object.defineProperty(this, '__ob__', {  
      enumerable: false,  configurable: false,
      writable: false, value: false,
    });
  }
}

هذه في الغالب مشكلة للمكتبات المستخدمة في تطبيقات Vue (على الأقل بالنسبة لي).

كيف تخبر Vue أن تراقب فقط (حدد الخاصية) لعمق البيانات على مستوى 1؟

حالتي هي ، أريد أن يتم إعلام Vue عند تغيير data.curObj ،
لكن لا تفعل ذلك باستخدام curObj.position ، curObj.rotation ، إلخ.

كنت أستخدم Object.freeze ، لكن في هذه الحالة ، قد يتسبب ذلك في حدوث خطأ عندما يحاول three.js تعيين قيم للكائن.

هل يجب علي القيام بما يلي؟
(في الواقع فعلت ذلك في مكان آخر مشابه)

data () {
  return {
    wrapper: Object.freeze({
      actual: [bigData]
    })
  }
},
methods: {
  operation () {
    this.wrapper = Object.freeze({
      actual: [newBigData]
    })
  }
}

// core/observer/watch.js
function _traverse (val: any, seen: ISet) {
  let i, keys
  const isA = Array.isArray(val)
  if ((!isA && !isObject(val)) || !Object.isExtensible(val)) {
    return
  }
  // ...
// core/observer/index.js
export function observe (value: any, asRootData: ?boolean): Observer | void {
  if (!isObject(value) || value instanceof VNode) {
    return
  }
  let ob: Observer | void
  if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    ob = value.__ob__
  } else if (
    observerState.shouldConvert &&
    !isServerRendering() &&
    (Array.isArray(value) || isPlainObject(value)) &&
    Object.isExtensible(value) &&
    !value._isVue
  ) {
    ob = new Observer(value)
  }
  // ...
> curObj PerspectiveCamera {uuid: "BD3C14DF-8C2B-4B96-9900-B3DD0EAC1163", name: "PerspectiveCamera", type: "PerspectiveCamera", parent: null, children: Array(0), …}

> Lodash.isPlainObject(curObj) false
> Vue.isPlainObject(curObj) true
  1. هل يمكننا إضافة شرط آخر للمستخدم لتعطيل المراقبة من مجرد Object.isExtensible ( Object.freeze
  2. هل يمكننا تحسين اكتشاف Vue.isPlainObject؟

يمكنك استخدام التدمير

var newObj = { ...obj };

هذا يجب أن يصلحه. سيجعل طريقة isPlainObject ترجع خطأ.

/**
 * Makes an object and it's children unobservable by frameworks like Vuejs
 */
class Unobservable {
  /**
   * Overrides the `Object.prototype.toString.call(obj)` result
   * <strong i="6">@returns</strong> {string} - type name
   * <strong i="7">@see</strong> {<strong i="8">@link</strong> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag}
   */
  get [Symbol.toStringTag]() {
    // Anything can go here really as long as it's not 'Object'
    return 'ObjectNoObserve';
  }
}
>> Object.prototype.toString.call(new Unobservable());
   "[object ObjectNoObserve]"

مرحبًا بالجميع ، هناك نقطة واحدة ضاعت في الردود وهي أن البيانات الموجودة في التعليق الأصلي ليست حالة خالصة . في حالتي ، لدي مثيل نموذج بمرجع خاص إلى ذاكرة التخزين المؤقت للبحث عن علاقة. على سبيل المثال ، يمكن لـ article البحث عن author أو comments . عندما أستدعي article.author ، يكون هذا بحث خاصية ديناميكيًا في ذاكرة التخزين المؤقت للعلاقة وليس وصولًا بسيطًا للسمات. اشياء قليلة لتأخذ في الاعتبار:

  • ذاكرة التخزين المؤقت ليست حالة خالصة ، لذلك لا أريد أن يتم ملاحظتها بواسطة Vue ، لأنها مضيعة للموارد.
  • لا يمكن تجاهل ذاكرة التخزين المؤقت ، لأنني ما زلت بحاجة إلى مرجع لإجراء عمليات البحث / التحديثات الديناميكية هذه.
  • تعتبر ذاكرة التخزين المؤقت مفردة بشكل فعال ويمكن تحديثها خارجيًا. يتم تحديث التطبيق وفقًا لذلك.

استجابة لبعض الاقتراحات:

  • استخدام JSON Stringify / parse أو إتلاف الكائن ليس كافيًا ، لأن هذا يكرر الكائن وذاكرة التخزين المؤقت ، بالإضافة إلى كسر المرجع إلى ذاكرة التخزين المؤقت الأصلية. لن يؤدي تحديث مرجع ذاكرة التخزين المؤقت الأصلي بعد الآن إلى تحديث مثيلات التطبيق. بدون عمليات البحث والتحديثات الديناميكية هذه ، تكون ذاكرة التخزين المؤقت غير مجدية بشكل أساسي ، وسيكون من الأفضل جعل الكائنات ذات الصلة سمات بسيطة في النموذج الأصلي. تجدر الإشارة أيضًا إلى أن هذه الاقتراحات تكسر طرق مثيل هذه الكائنات.
  • تكون الاقتراحات المقدمة من Mechazawa منطقية إذا كنت تتحكم في إنشاء الكتابة ، والأنواع مصممة للاستخدام مع Vue. في حالتي ، هذه مكتبة خارجية غير مرتبطة بـ Vue ، ولا أريد أن أخوض في مشكلة تغيير الأنواع في التطبيق. من السهل جدًا أن تقوم طبقة vue بتمييز بعض الخصائص المعروفة على أنها غير قابلة للرصد.

انتقادي الوحيد:

Vue-nonreactive لها Vue كتبعية وهي مبالغة عندما يتعلق الأمر بفعل شيء ما بشكل مباشر.

لست متأكدًا من سبب كون هذا أمرًا سيئًا؟ أنت تستخدم Vue بالفعل في تطبيقك ، والمكوِّن الإضافي خاص بـ Vue. إذا لم أكن مخطئًا ، فإن معظم أدوات البناء ذكية بما يكفي لعدم إنشاء حزم ذات تبعيات مكررة. بغض النظر ، هذا ليس صحيحًا . هناك تبعية للجهاز ، ولكن ليس تبعية لوقت التشغيل.


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

لذلك ، واجهت هذا مؤخرًا ، واكتشفت أن هناك طريقة أسهل بكثير لتقليل منطق مراقبة Vue: _تعريف خاصية على أنها غير قابلة للتكوين.

خلفية

في تطبيقي ، يجب أن أعمل مع مكتبة تابعة لجهة خارجية (OpenLayers) ، والتي تنشئ مثيلات فئة تحتوي على بيانات ولا تدعم أي نظام تفاعلي. لقد تسببت محاولة التقليل من الحذاء في الكثير من الصداع ، دعني أخبرك. لذا ، فإن الحل الوحيد القابل للتطبيق لتطبيق واسع النطاق باستخدام هذه المكتبة هو السماح لـ OpenLayers بالحصول على الأشياء بالطريقة التي يريدها ، وبالنسبة لي لجعل Vue يلعب بشكل أفضل مع هذه الكائنات المتداخلة بشكل فظيع. قبل العثور على هذه المشكلة ، كان تطبيقي يستخدم حوالي 3 العربات من ذاكرة الوصول العشوائي (على أكبر مجموعة بيانات لدينا) ، وكل ذلك بسبب جعل Vue هذه الكائنات تفاعلية. أيضًا ، كان الأمر بطيئًا حقًا عند التحميل. لقد جربت Vue-nonreactive ، وقد ساعدني ذلك ، ولكن فقط جعلنا نصل إلى حوالي 1 أزعج. قبل استخدام Vue ، كان التطبيق يجلس حول 350megs.

المحلول

أي شيء لا تريد أن يكون رد الفعل ، ما عليك سوى وضع علامة configurable: false . الأمر بسيط مثل:

Object.defineProperty(target, 'nested', { configurable: false });

(يؤدي هذا إلى إيقاف خاصية nested ، وجميع خصائصها من المراقبة.)

هذا هو! لا تبعية Vue ، ويمكن القول إنها غير صحيحة. مع ذلك ، انخفض طلبي إلى 200 ميغا مع أكبر مجموعة بيانات لدينا. إنه بسيط وسهل ويتطلب فقط تغييرًا في التوثيق من جانب Vue لجعله طريقة "رسمية" لعمل شيء غير تفاعلي.

مثير للاهتمام - يبدو بالتأكيد بديلاً قابلاً للتطبيق.

هل هناك طريقة لإيقاف تفاعل الملاحظة مؤقتًا وإلغاء الإيقاف المؤقت لاحقًا؟

لدي مراقب خاص ، ضمن ذلك أقوم بتحديث كائن ضخم حيث لا أريد تشغيل تحديث DOM إلا بعد الانتهاء من إعداد البيانات بالكامل.

intijk ليس بالضبط. انظر ، هذا يعتمد على ما تحاول القيام به ؛ يتعين على Vue في النهاية تطبيق حالتك ، لذا فإن التوقف المؤقت أثناء الحساب لا يساعد كثيرًا. إذا كنت ، بدلاً من ذلك ، تحاول تخطي الحالات المتوسطة ، وتطبيق الحالة النهائية فقط ، فابدأ فقط بكائن جديد ، ثم قم بتعيين هذا الكائن في النهاية.

على سبيل المثال (كود psuedocode):

doUpdate()
{
   const state = _.cloneDeep(this.myState);

  // Do intermediate state updates

  this.myState = state;
}

(تنطبق تحذيرات Normal Vue حول تفاعل الكائن.)

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

Morgul لقد استخدمت هذه الحيلة بالفعل لفترة طويلة ، لكن الحقيقة هي أنني لم أعد أرغب في استخدام هذه الحيلة بعد الآن.
في حالتي ، أصبح كائن البيانات الآن كبيرًا نوعًا ما ، ويتراوح من 2M إلى 100M ، ويعد إجراء نسخة عميقة على مثل هذا الكائن أمرًا مؤلمًا للغاية.

intijk هذا يبدو معقدًا بشكل لا يصدق لشيء يلزم Vue به. ما هي حالة الاستخدام هنا؟

تضمين التغريدة
لا أعتقد أن القضية معقدة ، فالحالة نفسها بسيطة ، فقط البيانات كبيرة نوعًا ما. في كل مرة تقوم الشبكة بتحميل بعض ملفات سجل التصور المفهرس ، ولدي عنصر تصور لعرضه.

هل لدى أي شخص أفكار حول تحديد حقل غير تفاعلي ضمن خاصية محسوبة؟ تعتمد فكرتي الأولى على عدم تفاعل الإحالة إلى المصفوفة ...

template: '<div v-html="markdown.render(input, env)"></div>',
props: ['id', 'input'],
computed: {
  env:      function() { return { reactive:this.id, non_reactive:[] } },
  markdown: function() { return Markdown },
},

// within markdown.render():
  env.non_reactive[0] = internal_data;

لكن هذا ليس توثيقًا ذاتيًا بالضبط :-)

مرحبا شباب. لقد وجدت هذه المشكلة للتو ووجدت أنني أواجه مشكلة تشبه إلى حد كبير مشكلة rpkilby: يقوم مشروعي ببناء سلسلة من Vue Virtual DOMs (أو تسمى vnode) من كائن JSON. سأستخدم كائن JSON هذا لإنشاء تطبيق android. على أي حال ، يمكن أن يكون كائن JSON ذا حجم كبير ، وعندما أستخدم JSON هذا في Vue ، ستلاحظه Vue. لقد جربت طريقة rpkilby's و Morgul ، لكنها لا تعمل. (راجع للشغل أنا في فريق ، بينما قد لا يكون بعض اللاعبين على دراية بـ Vue ، وربما يتسببون في ملاحظة JSON ، وإصدار Vue الخاص بي هو 2.5.16 ). أتساءل عما إذا كان بإمكاننا القيام بذلك في Vue traverse:
function _traverse (val، saw) {
فار ط ، مفاتيح ؛
var isA = Array.isArray (val) ؛
إذا ((! isA &&! isObject (val)) || Object.isFrozen (val) || قيمة مثيل VNode
|| (val && val ['__ vueNonReactive__'])) {
إرجاع
}
...
كما ترى ، أضفت "val && val ['__ vueNonReactive__']". ثم أقوم بتعديل كائن JSON ليحصل على "__vueNonReactive__ = true" مع العقدة الجذرية لـ JSON ، وهذا يحل مشكلتي.
أتساءل عما إذا كان هذا قد يسبب أي مشكلة؟ وهل سيعتبر هذا ميزة جديدة في Vue تمكن المطور من تكوين كائن ليتم ملاحظته بواسطة Vue أم لا من خلال تكوين خاصية الكائن؟ (قد يغير Object.freeze الكائن ليكون كائنًا غير قابل للتغيير ، لذلك لا تناسب كل حالة)

اعتبر هذا https://github.com/vuejs/vue/blob/v2.5.16/src/core/observer/index.js#L121
تعيين val._isVue = true يمكنه الهروب من إجراءات المراقبة vue.

التقيت اليوم بحالة ، لاحظت Vue مثيلًا لخريطة mapbox-gl ، ثم حدثت أشياء غريبة ، أصبحت الخريطة أخف وزناً. ولكن يجب أن يتم تمرير مثيل الخريطة بين مثيلات vue. بعد أن أضيف map._isVue = true ، تم حل المشكلة.

+1 لدعم ذلك رسميًا. أنا أستخدم كائنًا كبيرًا لا يحتاج إلى تفاعل في أحد المكونات ، وقد أدى تعطيل التفاعل غير المستخدم إلى تقليل حجم كائن الذاكرة من 800 ميجابايت إلى 43 ميجابايت
أنا أستخدم حل Mechazawa هو أفضل حل هنا على ما أعتقد.
لحل تعيين __ob__ 's configurable إلى أعمال خاطئة ولكنه يتسبب في تعطل Vue عندما يحاول تعيين __ob__ الحقيقي.

لقد أنشأت مكوّنًا إضافيًا Vue يجعل من الممكن جعل متغيرات Vue غير تفاعلية (يستخدم الخطاف beforeCreate).

هذا أنظف من vue- nonreactive -rpkilby ، يرجى إلقاء نظرة على هذا التعليق - لن يعمل الحل الخاص بك مع الإصدار التالي من Vue.


يرجى إلقاء نظرة على Vue-Static للحصول على طريقة لجعل المتغيرات غير تفاعلية.

<script>
export default {
    static() {
        return {
            map: null,
        };
    },
    mounted() {
        this.map = new mapboxgl.Map({...}); /* something heavy */
    },
};
</script>

مرحبًا samuelantonioli - يبدو أن vue-static يفعل شيئًا مختلفًا قليلاً ، ويعطل التفاعل لكائن بأكمله. في المقابل ، vue-nonreactive قادر على تعطيل الملاحظة لخاصية واحدة ، مع الحفاظ على رد فعل باقي الكائن.

ومع ذلك ، يبدو أن النوايا مختلفة قليلاً. لا تلاحظ الخصائص الثابتة التغييرات ، ولكن من المفترض أن يتم عرضها على قالب. لا يُقصد بالخصائص غير التفاعلية أن تتم ملاحظتها ولا يُقصد تقديمها.

على سبيل المثال ، يحتوي مثيل النموذج الخاص بي على مرجع إلى ذاكرة التخزين المؤقت للكائنات التي تتيح عمليات البحث عن الكائنات ذات الصلة. أريد ملاحظة / عرض instance و instance.author ، لكن ليس instance._cache .

new Vue({
    data() {
        const instance = postStore.fetch({include: ['author', 'comments.author']})
        Vue.nonreactive(instance._cache)

        return {post: instance, },
    },
    ...
});

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

LinusBorg - لا أرى فرعًا تجريبيًا. أين يتم تطوير الإصدار القادم؟

ما زلنا هو المفهوم / مرحلة التجربة ولم ننشر أي فرع بعد. لن يبدأ العمل الجاد في هذا الأمر قبل أن يكون لدينا التحديث 2.6 خارج الباب ، والذي سيستغرق في حد ذاته بعض العمل بعد أن نأمل أن يكون لدينا vue-cli 3.0 قريبًا جدًا

شكرا للتحديث.

لذلك لست متأكدًا من وجود المشكلة في نفس النطاق بمجرد تقديم وكلاء ES6. في طلبي ، أستخدمها بكثافة ، ويبدو أن حملها مقابل النفقات العامة للملاحظة الحالية لـ vue أصغر بكثير. أعتقد أن الشيطان يكمن في التفاصيل.

المشكلة التي أواجهها مع Vue-Static هي أنها تبدو زائدة عن الحاجة. يمكنني بناء الكائن الخاص بي في وحدة JS ، واستيراده ، ثم إعادة قيمته من دالة محسوبة ؛ نظرًا لأنه لن يتم ملاحظتها ، فلا يهم أن قيمة الوظيفة المحسوبة لن يتم إعادة حسابها أبدًا. وهذا فصل أفضل بكثير للمخاوف ، لأنني لا أقوم بأشياء من نوع منطق الأعمال في مكونات vue الخاصة بي.

على أي حال ، لا تزال خدعتي المتمثلة في تعيين الخصائص على أنها غير قابلة للتكوين هي الطريقة الأقل توغلاً والأقل اعتمادًا على Vue للتعامل مع المشكلة. ليس هناك أيضًا سبب لافتراض أنه سينفصل عن ES Proxies ؛ ربما لا تزال لا تريد ملاحظة الخصائص غير القابلة للتكوين. قد أكون مخطئًا تمامًا ، لكننا _ نعرف_ __ob__ سينتهي ... لا نعرف شيئًا عن التحقق من خاصية قابلة للتكوين.

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

أوافق ، إذا كنت تستخدم نمطًا آخر ، مثل استيراد الوحدات النمطية واستخدام الخصائص المحسوبة ، فلن تحتاج إلى Vue-Static . أنا فقط بحاجة إلى نمط يمكنني تعليمه لموظفيي يسهل عليهم فهمه واستخدامه. نمط استيراد الوحدة النمطية والاستخدام المحسوب ليس بهذا الوضوح IMO.


القليل من الوقت الإضافي: أنا متأكد من أن وكلاء ES6 وسيلة جيدة للذهاب ، لكن لدي بعض المخاوف بشأن توافق المتصفح (IE11 وما دونه لا يدعمه). أنا مهتم بما إذا كان سيكون هناك طبقة توافق / نوع من polyfill حتى نتمكن من استخدام Vue للمشاريع ذات متطلبات المتصفح الأكثر صرامة.

كيف تخبر Vue أن تراقب فقط (حدد الخاصية) لعمق البيانات على مستوى 1؟

+1 لهذه الفكرة ، سيكون من الأسهل هيكلة البيانات لاستخدام Vue مع مكتبة الرسوميات الخارجية (التي عادةً ما تحتوي على كائنات كبيرة متداخلة متعددة المستويات).

ماذا عن تحديد بعض الخصائص فقط لتكون تفاعلية؟

قد أفتقد شيئًا واضحًا هنا ، ولكن باستخدام this.propertyName = {/ * شيء كبير هنا * /} ؛
في الخطاف المركب () أليس حلاً لامتلاك خصائص غير ملحوظة؟

مرحبًاvlahanas. راجع https://github.com/vuejs/vue/issues/2637#issuecomment -403630456.

تعيين _isVue سيؤدي إلى تعطل vue-devtool ، استخدم هذه الوظيفة بدلاً من ذلك

export default function setIsVue(val) {
    if (!val) return

    Object.defineProperty(val, '_isVue', {
        value: true,
        enumerable: false,
        configurable: true,
    })

    // vue-devtool
    // https://github.com/vuejs/vue-devtools/blob/c309065c57f6579b778341ea37042fdf51a9fc6c/src/backend/index.js#L616
    // 因为有 _isVue 属性
    if (process.env.NODE_ENV !== 'production') {
        if (!val.$options) {
            Object.defineProperty(val, '$options', {
                value: {},
                enumerable: false,
                configurable: true,
            })
        }

        if (!val._data) {
            Object.defineProperty(val, '_data', {
                value: {},
                enumerable: false,
                configurable: true,
            })
        }
    }

    return val
}

لقد ضاعت في الضوضاء ولكن وضع علامة على خاصية على أنها غير قابلة للتكوين يبدو حقًا بمثابة الإصلاح.

Object.keys(scene).forEach((key)=>{
  Object.defineProperty(target, 'nested', { configurable: false });
});

لطيف حقًا عندما أحتاج إلى تمرير THREE.Scene ولكن لا أريد حرفيًا أن يصبح الرسم البياني للمشهد بأكمله في حالة من الفوضى التي يمكن ملاحظتها. وبعد ذلك لا يزال بإمكاني المرور حول الكائن الأصلي ويمكن أن يكون رد الفعل بناءً على ذلك. في احسن الاحوال!

لا تزال مشكلة.
لدي كائنات تحتوي على العديد من المستويات المتداخلة من الخصائص التي أريد الاحتفاظ بها غير التفاعلية.
1

حتى لو كنت أستخدم

لقد ضاعت في الضوضاء ولكن وضع علامة على خاصية على أنها غير قابلة للتكوين يبدو حقًا بمثابة الإصلاح.

Object.keys(scene).forEach((key)=>{
  Object.defineProperty(target, 'nested', { configurable: false });
});

لطيف حقًا عندما أحتاج إلى تمرير THREE.Scene ولكن لا أريد حرفيًا أن يصبح الرسم البياني للمشهد بأكمله في حالة من الفوضى التي يمكن ملاحظتها. وبعد ذلك لا يزال بإمكاني المرور حول الكائن الأصلي ويمكن أن يكون رد الفعل بناءً على ذلك. في احسن الاحوال!

أو

اعتبر هذا https://github.com/vuejs/vue/blob/v2.5.16/src/core/observer/index.js#L121
تعيين val._isVue = true يمكنه الهروب من إجراءات المراقبة vue.

التقيت اليوم بحالة ، لاحظت Vue مثيلًا لخريطة mapbox-gl ، ثم حدثت أشياء غريبة ، أصبحت الخريطة أخف وزناً. ولكن يجب أن يتم تمرير مثيل الخريطة بين مثيلات vue. بعد أن أضيف map._isVue = true ، تم حل المشكلة.

تصبح الخصائص في الكائنات المتداخلة تفاعلية.

حاولت القيام بذلك بشكل متكرر ، ولكن Maximum call stack size exceeded ، وهذا يسبب المزيد من التأخيرات.

Mitroright سيتعين عليك القيام بذلك بشكل متكرر ، لكنني أشك في أن

تكمن المشكلة هنا في كيفية تعامل Vue مع المصفوفات ؛ من المحتمل ألا ينجح وضع علامة على الخاصية غير القابلة للتكوين geoJsonData (لقد واجهت مشكلات مع ذلك ، لكنني لم أتعمق في "السبب").

جرب شيئًا كهذا:

function makeArrayNonConfigurable(objects)
{
    objects.forEach((obj) =>
    {
        Object.keys(obj).forEach((key) =>
        {
            Object.defineProperty(obj, key, { configurable: false });
        });
    });
}

نحن نتعمق بمستوى واحد فقط ، لأن هذا كل ما نحتاج إلى القيام به ؛ لن يبحث Vue في خصائص الكائن المتداخلة. ومع ذلك ، يبدو أنه ينظر إلى كائنات داخل المصفوفات على خصائص تم تمييزها على أنها غير قابلة للتكوين ، ومن هنا جاءت المشكلة التي تواجهها.

الآن ، سأخبرك أنه مع وجود 10000 عنصر يمر عبر هذا سوف يتخبط لبضع ثوان أو نحو ذلك في المرة الأولى التي يمر فيها عبر هذه المصفوفة ؛ يجب النظر إلى هذا على أنه مجرد جزء من تكلفة استرداد هذه البيانات. بصراحة ، أوصي باستهلاك هذه الكائنات مع فئة (أستخدم فئة تقوم بإرجاع وكيل من مُنشئها) ، ثم تخزين هذه الكائنات مؤقتًا بواسطة معرف فريد ، إذا كنت تقوم بتحميلها أكثر من مرة واحدة خلال عمر التطبيق- امتداد. ولكن هذا حقًا أحد تفاصيل التصميم ، ولا يتعلق تمامًا بمشكلتك.

لقد وجدت الحل هنا:
https://medium.com/@deadbeef404/tell -vue-js-to-stop-اضاعة الوقت وتقديم أسرع -7c3f7d2acaab

باختصار ، اجعل وظيفة المنفعة:

import Vue from 'vue';

const Observer = (new Vue()).$data.__ob__.constructor;

export function makeNonreactive(obj) {
    obj.__ob__ = new Observer({});
}

مرحبًاMitoright. للإشارة فقط ، تصف المقالة شجاعة vue-nonreactive . الفرق هو ما إذا كنت تريد استخدام الكود كمكوِّن إضافي (عبر vue-nonreactive ) أو كوظيفة مساعد. أيضًا ، تم ذكر vue-nonreactive في التحديث أعلى وصف هذه المشكلة مباشرةً.

نظرًا لتحديث vue-devtool مرة أخرى ، فإن https://github.com/vuejs/vue/issues/2637#issuecomment -434154442 سيؤدي إلى تعطل vue-devtool مرة أخرى

أقترح vue-nonreactive مثل الحلول 😆

لجعل __ob__ بلا defineProperty

vue-free.js

import Vue from 'vue'

const Observer = new Vue().$data.__ob__.constructor

function prevent(val) {
    if (val) {
        // Set dummy observer on value
        Object.defineProperty(val, '__ob__', {
            value: new Observer({}),
            enumerable: false,
            configurable: true,
        })
    }

    return val
}

// vue global
Vue.VUE_FREE = prevent

// window
global.VUE_FREE = prevent

// default export
export default prevent

الشكل سأعطي 2 سنتي والحل في هذا الشأن.

لدي أيضًا مشكلات مماثلة في تنفيذ كل من مفهوم التجميد و المزيف أوبزيرفر. تأتي بياناتي من الخادم وهي عبارة عن سيناريو TreeNode متكرر ، يستخدم مشروعي أيضًا vuex في هذه الحالة مما أضاف طبقة إلى المشكلات التي تمت مشاهدتها. لقد حصلت باستمرار على Maximum call stack size exceeded بسبب حلقة object.keys vues. لقد جربت التجميد وتعيين البيانات داخل VNode مزيف ، لكن لا يبدو أن أيًا منهما يوقف مشكلات العودية.

لقد عدت أخيرًا إلى الوراء ولففت خصائصي "غير التفاعلية" باستخدام نمط الوحدة الكاشفة الكلاسيكي

هذه هي الفئة (ES6 / typecript) ولكن يمكن أيضًا تطبيق نفس الفئة في الوضع العادي

import {  first, forEach } from 'lodash';

export class TreeNode {
    internalRefsInstance: () => { getParent: () => TreeNode; setParent: (parent: TreeNode) => void; getChildNodes: () => TreeNode[]; setChildNode: (childNode: TreeNode) => number; };

    get visitedDate(): string | undefined {
        return this._visitedDates.get(this.id) || undefined;
    }

    isSelectedTreeNode: boolean = false;
    showSubheader: boolean = false;
    showHelp: boolean = false;
    treeNodeIconName: string = 'empty';
    childTreeNodeCount: number = 0;

    constructor(public id: string,
        public componentName: string,
        private _visitedDates: Map<string, string>,
        public isActive: boolean = true,
        public nextFlow?: string,
        public prevFlow?: string,
        parent: TreeNode | undefined = undefined) {

        //invoke the internal refs module to create our static instance func to get the values from
        this.internalRefsInstance = this.nonReactiveModule();
        this.internalRefsInstance().setParent(parent);
    }
    nonReactiveModule = () => {
        let _parent: TreeNode | undefined = undefined;
        let _childNodes: TreeNode[] = [];
        const _getParent = (): TreeNode | undefined => {
            return _parent;
        };
        const _setParent = (parent: TreeNode | undefined): void => {
            _parent = parent;
        };
        const _getChildNodes = (): TreeNode[] => {
            return _childNodes || [];
        };
        const _setChildNode = (childNode: TreeNode): number => {
            if (!_childNodes) {
                _childNodes = [];
            }
            _childNodes.push(childNode);
            return _childNodes.length;
        };
        const returnObj = {
            getParent: _getParent,
            setParent: _setParent,
            getChildNodes: _getChildNodes,
            setChildNode: _setChildNode,
        };
        return () => { return returnObj; };
    }

    getParent(): TreeNode | undefined {
        return this.internalRefsInstance().getParent();
    }

    getChildNodes(): TreeNode[] {
        return this.internalRefsInstance().getChildNodes();
    }

    setChildNode(childFlow: TreeNode): void {
        this.childTreeNodeCount = this.internalRefsInstance().setChildNode(childFlow);
    }

    clone(parent: TreeNode | undefined = undefined): TreeNode {
        const newInstance = new TreeNode(this.id, this.componentName, this._visitedDates, this.isActive, this.nextFlow, this.prevFlow, parent);
        newInstance.showHelp = this.showHelp;
        newInstance.showSubheader = this.showSubheader;
        newInstance.isSelectedTreeNode = this.isSelectedTreeNode;
        forEach(this.getChildNodes(), (flow: TreeNode) => {
            newInstance.childTreeNodeCount = newInstance.internalRefsInstance().setChildNode(flow.clone(newInstance));
        });
        return newInstance;
    }

    setVisitedDates(visitedDates: Map<string, string>): void {
        this._visitedDates = visitedDates;
        forEach(this.getChildNodes(), (flow: TreeNode) => {
            flow.setVisitedDates(visitedDates);
        });
    }

    setAsSelected(setParent: boolean = true, setAllFirstChildren: boolean = true): void {
        this.isSelectedTreeNode = true;
        if (setAllFirstChildren) {
            const firstChildFlow = first(this.getChildNodes());
            if (firstChildFlow) {
                firstChildFlow.setAsSelected(false, true);
            }
        }

        if (setParent && this.getParent()) {
            this.getParent()!.setAsSelected(setParent);
        }
    }
    resetSelected(resetChildren: boolean = true): void {
        this.isSelectedTreeNode = false;
        if (resetChildren) {
            forEach(this.getChildNodes(), (flow: TreeNode) => {
                flow.resetSelected(resetChildren);
            });
        }
    }
}

لم تنجح المحسوبة في حالتي لأنني ما زلت بحاجة إلى الكائن الكامل وليس معالجًا يرسل لي التغيير على الحساب. على الأقل إذا فهمت كيف سيعمل المراقب العميق ضد نتيجة محسوبة فرعية.

أعتقد أن أخذ هذا إلى المستوى التالي سيكون إنشاء مساعد أو ديكور محقون غير متسلسل لتسريع العملية. أي تغذية مرتدة مفيدة ستكون رائعة.

يبدو أن شخصًا ما حل هذه المشكلة بالفعل ،

آمل أن تتحقق من جميع التفاصيل على https://github.com/vuejs/vue/issues/4384

مرحبًا ، لقد أنشأت # 10265 خاصة وأنني لم أكن على علم بهذه المشكلة السابقة.
أنا فقط أتساءل ما هو الحل الموصى به ليكون دليلاً في المستقبل وأن يظل متوافقًا مع Vue عندما يستخدم Proxy.
استخدام Object.defineProperty مع configurable: false يعمل بشكل جيد (لكنه لا يمنع خاصية وجود واضع / برنامج حالي لتصبح تفاعلية).
هل ستظل هذه التقنية قابلة للاستخدام مع Vue 3؟
شكرا

@ colin-guyon configurable: false المحتمل _not_ العمل ، خاصة أنه يبدو أن هناك https://github.com/vuejs/vue-next/blob/d9c6ff372c10dde8b496ee32f2b9a246edf66a35/packages/reactivity/src/reactive.ts#L159 . إذا انتهى الأمر في Vue 3.x ، فستكون هناك واجهة برمجة تطبيقات رسمية لتمييز كائن غير تفاعلي.

لاحظ أنه تمامًا مثل Vue.observable الجديد المقترح ، عندما يتم تعيين خاصية على كائن تفاعلي ، لن يتم تلطيخ هذه القيمة _ الجديدة وسيتم تركها كما هي. بدلاً من ذلك ، سيعيد _getter_ وكيلًا تفاعليًا له ، مما يؤدي إلى إنشاء واحد إذا لم يكن موجودًا بالفعل في ذاكرة التخزين المؤقت.

الخبر السار هو أنه طالما أنك لا تفعل الكثير على هذا الوكيل التفاعلي ، فمن المحتمل أن تكون بخير. إذا كان استنزاف الذاكرة أو قابلية التشغيل البيني مصدر قلق ، فلا داعي بالتأكيد للقلق بشأن ذلك لأنه مهما كان الكائن - مجموعة ضخمة من البيانات أو بعض الأشياء الغريبة من مكتبة والتي لا يمكن التنبؤ بالسلوك يجب تطبيق التفاعلية عليها ، كما تقول - _لا شيء _ يتم التطرق إليه بعد كل شيء. بهذا المعنى ، يحل Vue 3.x في الواقع الكثير من حالات الركن حيث ستكون هذه الميزة مفيدة لولا ذلك.

في الوقت الحالي ، يبدو أن رمز vue-next يستبعد مفاتيح الرموز من التفاعل ، تمامًا مثل ما يفعله الإصدار الحالي من Vue.

اعتبر هذا https://github.com/vuejs/vue/blob/v2.5.16/src/core/observer/index.js#L121
تعيين val._isVue = true يمكنه الهروب من إجراءات المراقبة vue.

التقيت اليوم بحالة ، لاحظت Vue مثيلًا لخريطة mapbox-gl ، ثم حدثت أشياء غريبة ، أصبحت الخريطة أخف وزناً. ولكن يجب أن يتم تمرير مثيل الخريطة بين مثيلات vue. بعد أن أضيف map._isVue = true ، تم حل المشكلة.

كنت أستخدم هذه الطريقة حتى تعرضت للعض من قبل أدوات تطوير Vue لأنها ترى أن _isVue صحيح ويعتقد أن الكائن هو مثيل مكون Vue ولكنه ليس كذلك.

يبدو أن الاختراق الوحيد الذي رأيته بدون آثار جانبية خطيرة هو نهج OP مع مكتبة vue-nonreactive .

هل هناك حلول بديلة في V3 لهذا؟

HunderlineK الضحال ، الضحلة ، رد الفعل ، markRaw

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات