Vue: [fitur] Kemampuan untuk menonaktifkan pengamatan Vue

Dibuat pada 7 Apr 2016  ·  50Komentar  ·  Sumber: vuejs/vue

Memperbarui:
Jika ada yang akhirnya membutuhkan fungsi ini, saya telah merilisnya sebagai vue-nonreactive dengan peringatan yang sesuai dan semuanya.


Kami memiliki beberapa model non-polos di mana kami perlu menonaktifkan pengamatan dan berjalan Vue. Contohnya adalah model sumber daya yang memiliki akses ke cache sehingga dapat mencari sumber daya terkait. Ini menyebabkan semua objek dalam cache menjadi diawasi (mungkin tidak efisien), serta beberapa interaksi tambahan dengan kode lain. Saat ini, kami menyiasatinya dengan menyetel Pengamat dummy pada cache. Sesuatu yang mirip dengan...

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;
            });
        },
    },
});

Ini berhasil, tapi

  • bergantung pada internal vue
  • memerlukan objek yang sudah diamati karena kita tidak dapat mengimpor kelas Observer secara langsung.

Usul:
Tambahkan metode resmi untuk secara eksplisit menonaktifkan observasi/jalan kaki Vue. misalnya, sesuatu seperti ...

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);

Pertimbangan:

  • Apa yang harus terjadi jika pengguna menetapkan jalur kunci reaktif ke objek non-reaktif? Haruskah vue memperingatkan pengguna? misalnya,

``` js
vm.$set('a', Vue.nonreactive({});

// berbeda dari..
vm.$set('a', {
someKey: Vue.nonreactive({}),
});
```

  • Haruskah objek yang sudah reaktif memperingatkan pengguna jika berusaha dibuat non-reaktif? misalnya,

``` js
// kesalahan
Vue.nonreactive(vm.$data.a)

// sah
Vue.nonreactive(_.clone(vm.$data.a));
```

Komentar yang paling membantu

  1. Jika Anda perlu melewatkan pengamatan untuk objek/array di data , gunakan Object.freeze() di atasnya;
  2. Anda tidak perlu meletakkan objek di data untuk mengaksesnya di this . Jika Anda hanya melampirkannya ke this di created() hook, itu tidak akan diamati sama sekali.

Semua 50 komentar

Tidakkah Object.freeze() tidak akan berfungsi dalam kasus Anda? Ini didukung sejak v1.0.18

  1. Jika Anda perlu melewatkan pengamatan untuk objek/array di data , gunakan Object.freeze() di atasnya;
  2. Anda tidak perlu meletakkan objek di data untuk mengaksesnya di this . Jika Anda hanya melampirkannya ke this di created() hook, itu tidak akan diamati sama sekali.
  • Object.freeze tidak berfungsi di sini. Cache diperbarui dari waktu ke waktu.
  • Sumber daya utama _is_ reaktif. Saya sebagian besar tertarik untuk membuat objek cache bersarang menjadi non-reaktif.

Maka mungkin sudah waktunya untuk memikirkan kembali desain model Anda. Mengapa meletakkan benda-benda itu di bawah sesuatu yang harus diamati?

Karena cache digunakan untuk mencari sumber daya terkait secara dinamis.

misalnya, kita dapat memiliki model Author dan Post . Model penulis mendefinisikan hubungan ke-banyak yang disebut posts ke model posting. Cache ini berisi data hubungan, serta koleksi terkait.

memanggil author.posts mendapatkan kiriman dari cache.

Secara desain, Vue tidak menyarankan untuk menempatkan objek kompleks dengan mekanisme mutasi statusnya sendiri ke dalam data instance Vue. Anda seharusnya hanya menempatkan status murni sebagai data yang diamati ke dalam instance Vue. Anda dapat memanipulasi status ini sesuka Anda, tetapi objek yang bertanggung jawab atas manipulasi tersebut tidak boleh menjadi bagian dari status instance Vue.

Pertama, pertanyaan klarifikasi - apa sebenarnya yang Anda maksud dengan keadaan murni ? Kami memiliki dua jenis negara:

  • status model (permanen, data disinkronkan dengan toko. misalnya, todo)
  • status vue (sementara, data yang mengontrol perilaku tampilan. mis., ciutkan/tampilkan daftar tugas)

Tapi bagaimanapun:
Itu adil. Modelnya pasti 'kompleks', jadi permintaan ini bertentangan dengan praktik terbaik saat ini. Juga, contoh awal saya tidak terlalu bagus - hanya itu yang berhasil menonaktifkan pengamatan. Ini lebih mewakili pengaturan kami saat ini dengan kemungkinan penggunaan:

<!-- 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,
    },
    ...
});

Pada dasarnya, kami memiliki vue induk yang bertanggung jawab untuk menempatkan komponen yang dapat digunakan kembali dalam tata letak dan mengambil/mengikat data ke komponen terkait. Komponen turunan tidak mengambil datanya sendiri karena datanya berbeda dalam konteks yang berbeda. misalnya, daftar komentar _pengguna_ vs. daftar komentar _postingan_.

Modelnya cukup 'bodoh' dengan pengecualian bahwa objek terkait tidak bersarang ( {post: {author: {}, comments: []}} ), tetapi malah dicari dari cache. misalnya, post.comments[2].author mungkin objek yang sama persis dengan post.author . Jadi, alih-alih memiliki banyak salinan objek penulis, kami hanya memiliki satu yang dicari dari cache. Tidak ada mutasi di atas - semua data dibuat pada pengambilan awal.

Juga, bukan karena permintaan itu relevan lagi, tetapi alternatifnya mungkin untuk tidak mengamati anggota objek 'pribadi'. Ini bisa menjadi anggota dengan garis bawah tunggal atau mungkin ganda. Kelemahan dari pendekatan ini adalah bahwa itu akan merusak perubahan.

Jika ada yang akhirnya membutuhkan fungsi ini, saya telah merilisnya sebagai vue-nonreactive dengan peringatan yang sesuai dan semuanya.

@rpkilby terima kasih telah berbagi!

@rpkilby Salah satu cara saya menyalin objek dan menghapus yang dapat diamati/reaktivitas

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

Sangat berguna karena saya ingin menyimpan array "status" dan mengimplementasikan objek histori status di vuex.

Sunting : Solusi ini khusus untuk kasus saya. Saya memiliki objek di mana saya hanya membutuhkan salinan nilai properti pada saat tertentu. Saya tidak peduli dengan referensi, pembaruan dinamis, dll.

Saat ini membekukan objek bukanlah solusi jangka panjang. [Vue-nonreactive] memiliki Vue sebagai ketergantungan yang berlebihan ketika harus melakukan sesuatu yang lurus ke depan. Bukankah pemeriksaan sederhana dalam kode seperti instance.__ob__ !== false sudah cukup? Ini akan memungkinkan perpustakaan untuk memastikan bahwa hal-hal seperti cache tidak akan diamati.

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

Ini sebagian besar merupakan masalah untuk perpustakaan yang digunakan dalam aplikasi Vue (setidaknya untuk saya).

Bagaimana cara memberi tahu Vue untuk hanya menonton (mendefinisikan Properti ke) kedalaman data 1 level?

Kasus saya adalah, saya ingin Vue mendapat pemberitahuan ketika data.curObj diubah,
tapi jangan dengan curObj.position , curObj.rotation , dll.

Saya dulu menggunakan Object.freeze , tetapi dalam kasus ini, itu akan menyebabkan Kesalahan ketika three.js mencoba memberikan nilai ke objek.

Apakah saya harus melakukan hal di bawah ini?
(sebenarnya saya melakukannya di tempat lain yang serupa)

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. Bisakah kita menambahkan kondisi lain bagi pengguna untuk menonaktifkan pengamatan selain dengan Object.isExtensible ( Object.freeze )?
  2. Bisakah kita meningkatkan deteksi Vue.isPlainObject?

Anda dapat menggunakan destructuring

var newObj = { ...obj };

Ini harus memperbaikinya. Ini akan membuat metode isPlainObject kembali salah.

/**
 * 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]"

Hai semua, satu hal yang hilang dalam tanggapan adalah bahwa data dalam komentar asli tidak murni . Dalam kasus saya, saya memiliki contoh model dengan referensi pribadi ke cache pencarian hubungan. Misalnya, article dapat mencari author atau comments . Ketika saya memanggil article.author , ini adalah pencarian properti dinamis ke dalam cache hubungan itu dan bukan akses atribut sederhana. Beberapa hal yang perlu dipertimbangkan:

  • Cache bukan status murni, jadi saya tidak ingin itu diamati oleh Vue, karena itu membuang-buang sumber daya.
  • Cache tidak dapat dibuang, karena saya masih memerlukan referensi untuk melakukan pencarian/pembaruan dinamis ini.
  • Cache secara efektif tunggal dan dapat diperbarui secara eksternal. Pembaruan aplikasi sesuai.

Menanggapi beberapa saran:

  • Menggunakan stringify/parse JSON atau perusakan objek tidak cukup, karena ini menduplikasi objek & cache, serta memutus referensi ke cache asli. Memperbarui referensi cache asli tidak akan lagi memperbarui instance aplikasi. Tanpa pencarian dan pembaruan dinamis ini, cache pada dasarnya tidak ada gunanya, dan akan lebih baik untuk membuat objek terkait menjadi atribut sederhana pada model aslinya. Juga perlu diperhatikan, saran ini mematahkan metode instan dari objek-objek ini.
  • Saran dari @Mechazawa masuk akal jika Anda mengontrol pembuatan tipe, dan tipe dibuat untuk digunakan dengan Vue. Dalam kasus saya, ini adalah perpustakaan eksternal yang tidak terikat dengan Vue, dan saya tidak ingin repot mengubah tipe dalam aplikasi. Jauh lebih mudah bagi lapisan vue untuk hanya menandai properti tertentu yang diketahui sebagai tidak dapat diamati.

Satu-satunya kritik saya:

Vue-nonreactive memiliki Vue sebagai ketergantungan yang berlebihan ketika harus melakukan sesuatu yang lurus ke depan.

Saya tidak yakin mengapa ini akan menjadi hal yang buruk? Anda sudah menggunakan Vue di aplikasi Anda, dan plugin khusus untuk Vue. Jika saya tidak salah, sebagian besar alat build cukup pintar untuk tidak membuat bundel dengan dependensi duplikat. Bagaimanapun, ini tidak benar . Ada ketergantungan dev, tetapi bukan ketergantungan runtime.


Bagaimanapun, saya senang melihat posting ini telah menarik minat, dan saya yakin beberapa solusi lain ini akan berfungsi dalam berbagai kasus lain. Saya hanya ingin menyoroti persyaratan dari komentar asli saya dan mengapa saran tersebut bukan alternatif yang cocok untuk kasus itu.

Jadi, saya baru-baru ini mengalami ini, dan menemukan bahwa ada cara yang lebih mudah untuk menghubungkan logika observasi Vue: _Define a property as non-configurable._

Latar belakang

Dalam aplikasi saya, saya harus bekerja dengan perpustakaan pihak ketiga (OpenLayers), yang membuat instance kelas yang menyimpan data, dan tidak mendukung sistem reaktivitas apa pun. Mencoba menyetir satu telah menyebabkan begitu banyak sakit kepala, izinkan saya memberi tahu Anda. Jadi, satu-satunya solusi yang layak untuk aplikasi skala besar yang menggunakan perpustakaan ini adalah membiarkan OpenLayers memiliki hal-hal seperti yang diinginkannya, dan bagi saya untuk membuat Vue bermain lebih bagus dengan objek-objek malapetaka yang sangat bersarang ini. Sebelum menemukan masalah ini, aplikasi saya menggunakan sekitar 3 giga ram (pada kumpulan data terbesar kami), semuanya disebabkan oleh Vue yang membuat objek ini reaktif. Juga, itu sangat lambat saat memuat. Saya mencoba Vue-nonreactive, dan itu membantu, tetapi hanya membuat kami turun menjadi sekitar 1 pertunjukan. Sebelum menggunakan Vue, aplikasi itu duduk di sekitar 350 MB.

Larutan

Apa pun yang Anda tidak ingin reaktif, cukup tandai sebagai configurable: false . Ini sesederhana:

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

(Ini menghentikan properti nested , dan semua propertinya untuk diamati.)

Itu dia! Tidak ada ketergantungan Vue, dan bisa dibilang bahkan tidak salah. Dengan itu, aplikasi saya turun hingga 200 MB dengan kumpulan data terbesar kami. Ini sederhana, dan mudah, dan hanya memerlukan perubahan dokumentasi di sisi Vue untuk menjadikannya cara 'resmi' untuk membuat sesuatu yang non-reaktif.

Menarik - sepertinya merupakan alternatif yang layak.

Apakah ada cara untuk menghentikan sementara pengamatan reaktif dan membatalkannya nanti?

Saya memiliki pengamat prop, di dalamnya saya memperbarui objek besar di mana saya tidak ingin memicu pembaruan DOM hanya setelah seluruh persiapan data selesai.

@intijk Tidak persis. Lihat, itu tergantung pada apa yang Anda coba lakukan; Vue akhirnya harus menerapkan status Anda, jadi berhenti sejenak saat dihitung tidak banyak membantu. Sebaliknya, jika Anda mencoba melewati status perantara, dan hanya menerapkan status akhir, mulailah dengan objek baru, lalu tetapkan objek itu di akhir.

Misalnya (psuedocode):

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

  // Do intermediate state updates

  this.myState = state;
}

(Peringatan Vue Normal tentang reaktivitas objek berlaku.)

Rekomendasi saya adalah menggunakan trik configurable untuk melewati bagian objek besar Anda yang tidak perlu reaktif. Jika semuanya _does_ perlu reaktif, saya sarankan menggunakan sesuatu seperti vuex .

@Morgul Saya sudah lama menggunakan trik ini, tetapi kenyataannya saya tidak lagi ingin menggunakan trik ini.
Dalam kasus saya, objek data sekarang agak besar, berkisar dari 2M hingga 100M, melakukan salinan dalam pada objek seperti itu cukup menyakitkan.

@intijk Kedengarannya sangat rumit untuk sesuatu untuk mengikat Vue. Apa kasus penggunaan di sini?

@Morgul
Saya tidak berpikir kasingnya rumit, kasingnya sendiri sederhana, hanya datanya yang agak besar. Setiap kali jaringan akan memuat beberapa file log visualisasi yang diindeks, dan saya memiliki komponen visualisasi untuk menampilkannya.

Adakah yang punya pemikiran untuk mendefinisikan bidang non-reaktif dalam properti yang dihitung? Ide pertama saya tergantung pada non-reaktivitas penugasan ke array ...

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;

Tapi itu tidak sepenuhnya mendokumentasikan diri sendiri :-)

Hai teman-teman. Saya baru saja menemukan masalah ini dan menemukan bahwa saya menghadapi masalah yang mirip dengan masalah rpkilby: proyek saya membuat serangkaian Vue Virtual DOM (atau disebut vnode) dari objek JSON. Saya akan menggunakan objek JSON ini untuk membuat aplikasi Android. Bagaimanapun, objek JSON ini bisa berukuran besar, dan ketika saya menggunakan JSON ini di Vue, itu akan diamati oleh Vue. Saya mencoba cara rpkilby dan Morgul, tetapi tidak berhasil. (BTW saya dalam tim, sementara beberapa orang mungkin tidak cukup akrab dengan Vue, dan mereka mungkin akan menyebabkan JSON diamati, dan Versi Vue saya adalah 2.5.16 ). Saya ingin tahu apakah kita bisa melakukan ini di Vue traverse:
function _traverse (val, terlihat) {
var i, kunci;
var isA = Array.isArray(val);
if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode
|| (val && val['__vueNonReactive__'])) {
kembali
}
...
Seperti yang Anda lihat, saya menambahkan "val && val['__vueNonReactive__']". Kemudian saya memodifikasi objek JSON saya agar memiliki "__vueNonReactive__ = true" dengan simpul akar JSON, dan ini menyelesaikan masalah saya.
Saya ingin tahu apakah ini dapat menyebabkan masalah? Dan apakah ini akan dianggap sebagai fitur baru di Vue yang memungkinkan pengembang dapat mengkonfigurasi objek untuk diamati oleh Vue atau tidak dengan mengkonfigurasi properti objek? (Object.freeze dapat mengubah objek menjadi objek yang tidak dapat diubah, sehingga tidak cocok untuk setiap situasi)

pertimbangkan ini https://github.com/vuejs/vue/blob/v2.5.16/src/core/observer/index.js#L121
set val._isVue = true dapat keluar dari prosedur amati vue.

Hari ini saya menemukan kasus bahwa, Vue mengamati contoh peta dari mapbox-gl, kemudian hal-hal aneh terjadi, peta menjadi lebih ringan. Tetapi instance peta harus diteruskan di antara instance vue. Setelah saya menambahkan map._isVue = true , masalah teratasi.

+1 untuk mendukung itu secara resmi. Saya menggunakan objek besar yang tidak memerlukan reaktivitas dalam suatu komponen, dan menonaktifkan reaktivitas yang tidak digunakan mengurangi ukuran objek memori dari 800MB menjadi 43MB
Saya menggunakan solusi @magicdawn untuk masalah kompatibilitas, tetapi saya pikir @Mechazawa adalah solusi terbaik di sini.
Untuk solusi pengaturan __ob__ 's configurable ke false works tetapi membuat Vue crash ketika mencoba untuk mengatur real __ob__ .

Saya telah membuat plugin Vue yang memungkinkan variabel Vue menjadi non-reaktif (menggunakan kait beforeCreate).

Ini lebih bersih daripada vue- nonreactive - komentar ini - solusi Anda tidak akan berfungsi untuk versi Vue berikutnya.


Silakan lihat Vue-Static untuk cara membuat variabel non-reaktif.

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

Hai @samuelantonioli - sepertinya vue-static melakukan sesuatu yang sedikit berbeda, menonaktifkan reaktivitas untuk seluruh objek. Sebaliknya, vue-nonreactive mampu menonaktifkan observasi untuk satu properti , sambil menjaga objek lainnya tetap reaktif.

Yang mengatakan, sepertinya niatnya sedikit berbeda. Properti statis tidak mengamati perubahan, tetapi dimaksudkan untuk dirender ke template. Sifat non-reaktif tidak dimaksudkan untuk diamati, juga tidak dimaksudkan untuk dirender.

misalnya, contoh model saya memiliki referensi ke cache objek yang memungkinkan pencarian objek terkait. Saya ingin mengamati/render instance dan terkait instance.author , tetapi bukan instance._cache .

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

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

Apa pun itu, terima kasih atas perhatiannya. Saya harus melihat bagaimana versi berikutnya menggunakan proxy dan melihat apakah ada cara untuk menipu pembuatan observer/proxy.

@LinusBorg - Saya tidak melihat cabang eksperimental. Di mana pengembangan berlangsung untuk versi berikutnya?

Kami masih tahap konsep/eksperimen dan belum menerbitkan cabang. Pekerjaan serius dalam hal ini tidak akan dimulai sebelum kami meluncurkan pembaruan 2.6, yang dengan sendirinya akan membutuhkan beberapa pekerjaan setelah kami berharap vue-cli 3.0 segera dirilis.

Terima kasih untuk pembaruannya.

Jadi saya tidak yakin bahwa masalahnya ada dalam lingkup yang sama setelah Proksi ES6 diperkenalkan. Dalam aplikasi saya, saya banyak menggunakannya, dan overhead mereka vs overhead pengamatan vue saat ini tampaknya jauh lebih kecil. Setan akan ada di detailnya, saya kira.

Masalah yang saya miliki dengan Vue-Static adalah rasanya berlebihan. Saya dapat membangun objek saya dalam modul JS, mengimpornya, dan kemudian mengembalikan nilainya dari fungsi yang dihitung; karena tidak akan diamati, tidak masalah bahwa nilai fungsi yang dihitung tidak akan pernah dihitung ulang. Dan, itu adalah pemisahan masalah yang jauh lebih baik, karena saya tidak melakukan hal-hal ketik logika bisnis di komponen vue saya.

Bagaimanapun, trik saya untuk mengatur properti sebagai tidak dapat dikonfigurasi masih merupakan cara yang paling tidak invasif, paling tidak bergantung pada Vue untuk menangani masalah. Juga tidak ada alasan untuk berasumsi bahwa itu akan putus dengan ES Proxies; Anda mungkin masih tidak ingin mengamati properti yang tidak dapat dikonfigurasi. Saya bisa saja salah, tetapi kami _know_ __ob__ akan dihapus... kami tidak tahu tentang pemeriksaan properti yang dapat dikonfigurasi.

Plus, ini telah bekerja seperti jagoan dalam kode produksi kami selama 8+ bulan. ;) (Kami memiliki ruang masalah yang mirip dengan @samuelantonioli; kami memiliki peta OpenLayers yang perlu kami kerjakan di dalam Vue, tanpa membuat Vue menggembungkan memori kami menjadi 2,4 gigs...)

Saya setuju, jika Anda menggunakan pola lain misalnya modul impor dan menggunakan properti yang dihitung, Anda tidak memerlukan Vue-Static . Saya hanya membutuhkan pola yang dapat saya ajarkan kepada karyawan saya yang mudah dipahami dan digunakan oleh mereka. Pola import-module-and-use-computed-properties bukanlah IMO yang jelas.


Sedikit OT: Saya cukup yakin bahwa ES6 Proxies adalah cara yang baik, tetapi saya memiliki beberapa kekhawatiran tentang kompatibilitas browser (IE11 dan di bawahnya tidak mendukungnya). Saya tertarik jika akan ada lapisan kompatibilitas / beberapa jenis polyfill sehingga kami dapat menggunakan Vue untuk proyek dengan persyaratan browser yang lebih ketat.

Bagaimana cara memberi tahu Vue untuk hanya menonton (mendefinisikan Properti ke) kedalaman data 1 level?

+1 untuk ide ini, akan lebih mudah untuk menyusun data untuk menggunakan Vue dengan lib Grafik eksternal (yang biasanya memiliki objek besar bersarang multi-level).

Bagaimana hanya menentukan beberapa properti menjadi reaktif?

Saya mungkin melewatkan sesuatu yang jelas di sini, tetapi menggunakan this.propertyName = { /* something big here */ };
di hook mount() bukan solusi untuk memiliki properti yang tidak diamati?

set _isVue akan membuat vue-devtool crash, gunakan fungsi ini sebagai gantinya

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
}

Itu tersesat dalam kebisingan tetapi menandai properti sebagai tidak dapat dikonfigurasi sepertinya benar

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

Sangat bagus ketika saya harus membagikan THREE.Scene tetapi tidak ingin secara harfiah seluruh grafik adegan menjadi berantakan yang dapat diamati. Dan kemudian saya masih bisa menyebarkan objek asli dan itu bisa reaktif berdasarkan itu. Sempurna!

Masih masalah.
Saya memiliki objek yang berisi banyak tingkat properti bersarang yang ingin saya tahan non-reaktif.
1

Bahkan jika saya menggunakan

Itu tersesat dalam kebisingan tetapi menandai properti sebagai tidak dapat dikonfigurasi sepertinya benar

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

Sangat bagus ketika saya harus membagikan THREE.Scene tetapi tidak ingin secara harfiah seluruh grafik adegan menjadi berantakan yang dapat diamati. Dan kemudian saya masih bisa menyebarkan objek asli dan itu bisa reaktif berdasarkan itu. Sempurna!

atau

pertimbangkan ini https://github.com/vuejs/vue/blob/v2.5.16/src/core/observer/index.js#L121
set val._isVue = true dapat keluar dari prosedur amati vue.

Hari ini saya menemukan kasus bahwa, Vue mengamati contoh peta dari mapbox-gl, kemudian hal-hal aneh terjadi, peta menjadi lebih ringan. Tetapi instance peta harus diteruskan di antara instance vue. Setelah saya menambahkan map._isVue = true , masalah teratasi.

Properti di objek bersarang menjadi reaktif.

Saya mencoba melakukannya secara rekursif, tetapi Maximum call stack size exceeded , dan itu menyebabkan lebih banyak kelambatan.

@Mitroright Anda harus melakukan ini secara rekursif, tetapi saya menduga pendekatan Anda mungkin tidak sepenuhnya benar.

Masalahnya di sini adalah bagaimana Vue menangani Array; cukup menandai properti geoJsonData dapat dikonfigurasi kemungkinan tidak akan berfungsi (saya punya masalah dengan itu, tetapi tidak pernah menggali 'mengapa'.)

Cobalah sesuatu seperti ini:

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

Kami hanya naik satu tingkat, karena hanya itu yang perlu kami lakukan; Vue tidak akan melihat properti objek bersarang. Namun, tampaknya melihat objek di dalam array pada properti yang ditandai sebagai tidak dapat dikonfigurasi, oleh karena itu masalah yang Anda hadapi.

Sekarang, saya akan memberi tahu Anda bahwa dengan 10.000 objek yang melalui ini akan berputar selama beberapa detik atau lebih saat pertama kali melewati array ini; ini harus dilihat hanya sebagai bagian dari biaya pengambilan data ini. Terus terang, saya merekomendasikan untuk mengonsumsi objek-objek itu dengan kelas (saya menggunakan kelas yang mengembalikan proxy dari konstruktornya), dan kemudian menyimpan objek-objek itu dengan id unik, jika Anda memuatnya lebih dari satu kali selama hidup aplikasi- menjangkau. Tapi itu benar-benar detail desain, dan tidak sepenuhnya terkait dengan masalah Anda.

Saya menemukan solusi di sini:
https://medium.com/@deadbeef404/tell -vue-js-to-stop-wasting-time-and-render-faster-7c3f7d2acaab

Singkatnya, buat fungsi utilitas:

import Vue from 'vue';

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

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

Hai @Mitoright. Sekedar referensi, artikel ini menggambarkan nyali vue-nonreactive . Perbedaannya adalah apakah Anda ingin menggunakan kode sebagai plugin (melalui vue-nonreactive ) atau sebagai fungsi pembantu. Juga, vue-nonreactive disebutkan dalam pembaruan tepat di bagian atas deskripsi masalah ini.

Karena vue-devtool mendapat pembaruan lagi, https://github.com/vuejs/vue/issues/2637#issuecomment -434154442 akan membuat vue-devtool crash lagi

Saya menyarankan vue-nonreactive seperti solusi

untuk membuat __ob__ none dapat dihitung, gunakan 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

Gambar saya akan memberikan 2 sen dan solusi saya untuk ini.

Saya juga memiliki masalah serupa dalam menerapkan konsep Freeze dan Pengamat palsu. Data saya berasal dari server dan merupakan skenario TreeNode rekursif, Proyek saya juga menggunakan vuex dalam hal ini yang menambahkan lapisan ke masalah yang terlihat. Saya terus-menerus mendapat Maximum call stack size exceeded karena vues object.keys loop. Saya telah mencoba Bekukan dan mengatur data di dalam VNode palsu, tetapi sepertinya tidak ada yang menghentikan masalah rekursi.

Saya akhirnya melangkah mundur dan membungkus properti "non-reaktif" saya menggunakan Pola Modul Pengungkapan klasik

ini adalah kelasnya (ES6/typescript) tetapi hal yang sama dapat diterapkan di vue biasa juga

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);
            });
        }
    }
}

Computed tidak berfungsi dalam kasus saya karena saya masih membutuhkan objek penuh dan bukan pawang yang mengirimi saya perubahan pada yang dihitung. Setidaknya jika saya memahami bagaimana pengamat yang mendalam akan bekerja melawan hasil subset yang dihitung.

Saya pikir mengambil ini tingkat selanjutnya adalah membuat pembantu atau dekorator nonrekursif yang disuntikkan untuk mempercepat proses. Umpan balik yang bermanfaat akan sangat bagus.

sepertinya seseorang sudah memecahkan masalah ini,

harap Anda memeriksa semua detail di https://github.com/vuejs/vue/issues/4384

Hai, saya membuat #10265 terutama karena saya tidak mengetahui masalah sebelumnya.
Saya hanya ingin tahu apa solusi yang disarankan untuk menjadi bukti masa depan dan tetap kompatibel dengan Vue ketika akan menggunakan Proxy.
Menggunakan Object.defineProperty dengan configurable: false berfungsi dengan baik (tetapi tidak mencegah properti yang memiliki penyetel/pengambil yang ada menjadi reaktif).
Apakah teknik ini masih dapat digunakan dengan Vue 3 ?
Terima kasih

@colin-guyon configurable: false mungkin akan _not_ bekerja, terutama karena tampaknya ada https://github.com/vuejs/vue-next/blob/d9c6ff372c10dde8b496ee32f2b9a246edf66a35/packages/reactivity/src/reactive.ts#L159 . Jika berakhir di Vue 3.x, akan ada API resmi untuk menandai objek non-reaktif.

Perhatikan bahwa seperti yang baru diusulkan Vue.observable , ketika properti diatur pada objek reaktif, nilai _new_ itu tidak akan tercemar dan dibiarkan apa adanya. Sebagai gantinya, _getter_ akan mengembalikan proxy reaktif untuknya, membuatnya jika belum ada di cache.

Berita yang beruntung adalah, selama Anda tidak melakukan banyak hal pada proxy reaktif _that_, Anda mungkin akan baik-baik saja. Jika memory hog atau interoperabilitas menjadi perhatian maka Anda tentu tidak perlu khawatir tentang itu karena apa pun objeknya — kumpulan data raksasa atau objek asing dari perpustakaan yang perilakunya tidak dapat diprediksi jika reaktivitas diterapkan padanya, katamu — _tidak ada apa-apa_ tentang hal itu akan tersentuh, setelah semua. Dalam hal ini Vue 3.x sebenarnya memecahkan banyak kasus sudut di mana fitur ini seharusnya berguna.

Saat ini, kode vue-next tampaknya mengecualikan kunci simbol agar tidak reaktif, seperti yang dilakukan versi Vue saat ini.

pertimbangkan ini https://github.com/vuejs/vue/blob/v2.5.16/src/core/observer/index.js#L121
set val._isVue = true dapat keluar dari prosedur amati vue.

Hari ini saya menemukan kasus bahwa, Vue mengamati contoh peta dari mapbox-gl, kemudian hal-hal aneh terjadi, peta menjadi lebih ringan. Tetapi instance peta harus diteruskan di antara instance vue. Setelah saya menambahkan map._isVue = true , masalah teratasi.

Saya menggunakan metode ini sampai saya digigit oleh alat dev Vue yang menyadap karena melihat _isVue benar dan menganggap objek tersebut adalah instance komponen Vue tetapi tidak.

Satu-satunya peretasan yang saya lihat tanpa efek samping yang serius tampaknya adalah pendekatan OP dengan perpustakaan vue-nonreactive .

Apakah ada solusi alternatif di V3 untuk ini?

@HunderlineK dangkalRef, dangkalReaktif, markRaw

Apakah halaman ini membantu?
0 / 5 - 0 peringkat