Vue 3'te İsteğe Bağlı Reaktivite

Yayınlanan: 2022-03-11

Takdire şayan performans iyileştirmelerinin yanı sıra, yakın zamanda piyasaya sürülen Vue 3, birçok yeni özelliği de beraberinde getirdi. Muhtemelen en önemli giriş Kompozisyon API'sidir . Bu makalenin ilk bölümünde, yeni bir API için standart motivasyonu özetliyoruz: daha iyi kod organizasyonu ve yeniden kullanım. İkinci bölümde, Vue 2'nin tepkisellik sisteminde ifade edilemeyen tepkiselliğe dayalı özelliklerin uygulanması gibi yeni API'yi kullanmanın daha az tartışılan yönlerine odaklanacağız.

Buna isteğe bağlı tepkisellik diyeceğiz . İlgili yeni özellikleri tanıttıktan sonra, Vue'nun reaktivite sisteminin yeni ifadesini göstermek için basit bir elektronik tablo uygulaması oluşturacağız. En sonunda, talep üzerine tepkiselliğin bu iyileştirmeyi gerçek dünyada ne şekilde kullandığını tartışacağız.

Vue 3'teki Yenilikler ve Neden Önemli?

Vue 3, Vue 2'nin büyük bir yeniden yazımıdır ve eski API ile geriye dönük uyumluluğu neredeyse tamamen korurken çok sayıda iyileştirme sunar.

Vue 3'teki en önemli yeni özelliklerden biri Composition API'dir . Tanıtımı, ilk kez kamuoyunda tartışıldığında çok tartışmalara yol açtı. Yeni API'ye henüz aşina değilseniz, önce arkasındaki motivasyonu açıklayacağız.

Kod organizasyonunun olağan birimi, anahtarları bir bileşenin çeşitli olası türlerini temsil eden bir JavaScript nesnesidir. Bu nedenle, nesnenin reaktif veriler ( data ) için bir bölümü, hesaplanmış özellikler için başka bir bölümü ( computed ), bileşen yöntemleri ( methods ) için bir bölümü daha olabilir, vb.

Bu paradigma altında, bir bileşen, iç işleyişi yukarıda belirtilen bileşen bölümleri arasında dağıtılmış, birbiriyle ilişkisiz veya gevşek şekilde ilişkili birden fazla işlevselliğe sahip olabilir. Örneğin, temelde ayrı iki işlevi uygulayan dosyaları karşıya yüklemek için bir bileşenimiz olabilir: dosya yönetimi ve yükleme durumu animasyonunu kontrol eden bir sistem.

<script> bölümü aşağıdakine benzer bir şey içerebilir:

 export default { data () { return { animation_state: 'playing', animation_duration: 10, upload_filenames: [], upload_params: { target_directory: 'media', visibility: 'private', } } }, computed: { long_animation () { return this.animation_duration > 5; }, upload_requested () { return this.upload_filenames.length > 0; }, }, ... }

Kod organizasyonuna yönelik bu geleneksel yaklaşımın faydaları vardır, özellikle geliştiricinin yeni bir kod parçasını nereye yazacağı konusunda endişelenmesine gerek yoktur. Reaktif bir değişken ekliyorsak, onu data bölümüne ekliyoruz. Mevcut bir değişken arıyorsak, bunun data bölümünde olması gerektiğini biliyoruz.

İşlevsellik uygulamasını bölümlere ( data , computed , vb.) ayırmaya yönelik bu geleneksel yaklaşım, her durumda uygun değildir.

Aşağıdaki istisnalar sıklıkla belirtilir:

  1. Çok sayıda işlevselliğe sahip bir bileşenle uğraşmak. Örneğin, animasyon kodumuzu, animasyonun başlamasını geciktirme yeteneği ile yükseltmek istiyorsak, bir kod düzenleyicide bileşenin tüm ilgili bölümleri arasında kaydırma/atlamamız gerekecek. Dosya yükleme bileşenimiz söz konusu olduğunda, bileşenin kendisi küçüktür ve uyguladığı işlevlerin sayısı da azdır. Bu durumda, bölümler arasında geçiş yapmak gerçekten sorun değil. Bu kod parçalama sorunu, büyük bileşenlerle uğraştığımızda alakalı hale gelir.
  2. Geleneksel yaklaşımın eksik olduğu bir başka durum da kodun yeniden kullanılmasıdır. Çoğu zaman, birden fazla bileşende kullanılabilen belirli bir reaktif veri, hesaplanmış özellikler, yöntemler vb. kombinasyonu yapmamız gerekir.

Vue 2 (ve geriye dönük uyumlu Vue 3), kod düzenleme ve yeniden kullanım sorunlarının çoğuna bir çözüm sunar: mixins .

Vue 3'te Mixins'in Artıları ve Eksileri

Karışımlar, bir bileşenin işlevlerinin ayrı bir kod biriminde çıkarılmasına izin verir. Her işlevsellik ayrı bir karışıma konur ve her bileşen bir veya daha fazla karışım kullanabilir. Bir karışımda tanımlanan parçalar, bileşenin kendisinde tanımlanmış gibi bir bileşende kullanılabilir. Karışımlar, belirli bir işlevsellik ile ilgili kodu toplamaları bakımından nesne yönelimli dillerdeki sınıflara biraz benzer. Sınıflar gibi, karışımlar diğer kod birimlerinde miras alınabilir (kullanılabilir).

Bununla birlikte, karışımlarla akıl yürütme daha zordur, çünkü sınıfların aksine, karışımların kapsülleme akılda tutularak tasarlanmasına gerek yoktur. Karıştırmaların, dış dünyaya iyi tanımlanmış bir arayüz olmaksızın gevşek bir şekilde bağlanmış kod parçalarının koleksiyonları olmasına izin verilir. Aynı bileşende aynı anda birden fazla karışımın kullanılması, anlaşılması ve kullanılması zor bir bileşene neden olabilir.

Çoğu nesne yönelimli dil (örneğin, C# ve Java), nesne yönelimli programlama paradigmasının bu tür karmaşıklıkla başa çıkmak için araçlara sahip olmasına rağmen, çoklu kalıtımı caydırır ve hatta buna izin vermez. (Bazı diller, C++ gibi çoklu kalıtıma izin verir, ancak yine de kalıtım yerine kompozisyon tercih edilir.)

Vue'da mixins kullanırken ortaya çıkabilecek daha pratik bir sorun, ortak adlar bildiren iki veya daha fazla mixin kullanıldığında ortaya çıkan ad çakışmasıdır . Burada, Vue'nin ad çakışmalarıyla başa çıkmak için varsayılan stratejisi belirli bir durumda ideal değilse, stratejinin geliştirici tarafından ayarlanabileceği belirtilmelidir. Bu, daha fazla karmaşıklık getirme pahasına gelir.

Başka bir konu da, karışımların bir sınıf kurucusuna benzer bir şey sunmamasıdır. Bu bir sorundur, çünkü genellikle farklı bileşenlerde bulunmak için çok benzer, ancak tam olarak aynı olmayan işlevselliğe ihtiyacımız vardır. Bu, bazı basit durumlarda, karışım fabrikalarının kullanılmasıyla önlenebilir.

Bu nedenle, karışımlar kod organizasyonu ve yeniden kullanım için ideal çözüm değildir ve proje büyüdükçe sorunları daha ciddi hale gelir. Vue 3, kod organizasyonu ve yeniden kullanımla ilgili aynı sorunları çözmenin yeni bir yolunu sunar.

Composition API: Vue 3'ün Kod Organizasyonu ve Yeniden Kullanımına Cevabı

Composition API, bir bileşenin parçalarını tamamen ayırmamıza izin verir (ancak bunu gerektirmez). Her kod parçası (bir değişken, hesaplanan özellik, saat vb.) bağımsız olarak tanımlanabilir.

Örneğin, "oynatma" (varsayılan) değerine sahip bir animation_state anahtarını içeren bir data bölümü içeren bir nesneye sahip olmak yerine artık şunu yazabiliriz (JavaScript kodumuzun herhangi bir yerine):

 const animation_state = ref('playing');

Etki, bu değişkeni bazı bileşenlerin data bölümünde bildirmekle hemen hemen aynıdır. Tek temel fark, bileşenin dışında tanımlanan ref kullanmayı düşündüğümüz bileşende kullanılabilir hale getirmemiz gerektiğidir. Bunu, bileşenin tanımlandığı yere modülünü aktararak yapıyoruz ve bir bileşenin setup bölümünden ref . Şimdilik bu prosedürü atlayacağız ve bir an için yeni API'ye odaklanacağız. Vue 3'teki tepkisellik bir bileşen gerektirmez; aslında kendi kendine yeten bir sistemdir.

Bu değişkeni içe aktardığımız herhangi bir kapsamda animation_state değişkenini kullanabiliriz. Bir ref oluşturduktan sonra, gerçek değerini ref.value kullanarak alır ve ayarlarız, örneğin:

 animation_state.value = 'paused'; console.log(animation_state.value);

Atama operatörü aksi takdirde (reaktif olmayan) "duraklatıldı" değerini animation_state değişkenine atadığından, '.value' son ekine ihtiyacımız var. JavaScript'teki tepkisellik (hem Vue 2'deki gibi defineProperty aracılığıyla uygulandığında, hem de Vue 3'teki gibi bir Proxy dayalı olduğunda) anahtarları ile reaktif olarak çalışabileceğimiz bir nesne gerektirir.

Bunun Vue 2'de de geçerli olduğunu unutmayın; orada, herhangi bir reaktif veri üyesine ön ek olarak bir bileşenimiz vardı ( component.data_member ). JavaScript dil standardı, atama operatörünü aşırı yükleme özelliğini getirmedikçe ve getirmedikçe, reaktif ifadeler, istediğimiz herhangi bir atama işleminin sol tarafında görünmesi için bir nesne ve bir anahtar (örneğin, animation_state ve yukarıdaki gibi value ) gerektirecektir. reaktiviteyi koruyun.

Vue'nun şablon kodunu önceden işlemesi gerektiğinden ve referansları otomatik olarak algılayabildiğinden, şablonlarda .value atlayabiliriz:

 <animation :state='animation_state' />

Teoride, Vue derleyicisi, bir Tek Dosya Bileşeninin (SFC) <script> bölümünü de benzer şekilde önceden işleyebilir ve gerektiğinde .value . Bununla birlikte, refs kullanımı, SFC kullanıp kullanmamamıza bağlı olarak farklılık gösterecektir, bu nedenle belki de böyle bir özellik istenmeyebilir.

Bazen, asla tamamen farklı bir örnekle değiştirmeyi düşünmediğimiz bir varlığımız olur (örneğin, bir Javascript nesnesi veya bir dizi olabilir). Bunun yerine, yalnızca anahtarlı alanlarını değiştirmekle ilgilenebiliriz. Bu durumda bir kestirme yol vardır: ref yerine reactive kullanmak, .value vazgeçmemize izin verir:

 const upload_params = reactive({ target_directory: 'media', visibility: 'private', }); upload_params.visibility = 'public'; // no `.value` needed here // if we did not make `upload_params` constant, the following code would compile but we would lose reactivity after the assignment; it is thus a good idea to make reactive variables ```const``` explicitly: upload_params = { target_directory: 'static', visibility: 'public', };

ref ve reactive ile ayrıştırılmış reaktivite, Vue 3'ün tamamen yeni bir özelliği değildir. Çoğunlukla, Vue.observable ile reactive değiştirilebilir. Farklardan biri, Vue.observable doğrudan iletilen nesneye erişmenin ve onu mutasyona uğratmanın reaktif olması, yeni API'nin bir proxy nesnesi döndürmesidir, bu nedenle orijinal nesneyi değiştirmenin reaktif etkileri olmayacaktır.

Karşılaştırma: Seçenekler API'si ve Kompozisyon API'si.

Vue 3'te tamamen yeni olan şey, bir bileşenin diğer reaktif parçalarının da artık reaktif verilere ek olarak bağımsız olarak tanımlanabilmesidir. Hesaplanan özellikler beklenen bir şekilde uygulanır:

 const x = ref(5); const x_squared = computed(() => x.value * x.value); console.log(x_squared.value); // outputs 25

Benzer şekilde, çeşitli saat türleri, yaşam döngüsü yöntemleri ve bağımlılık enjeksiyonu uygulanabilir. Kısa olması adına, burada bunlara değinmeyeceğiz.

Vue geliştirme için standart SFC yaklaşımını kullandığımızı varsayalım. Veriler, hesaplanan özellikler vb. için ayrı bölümler içeren geleneksel API'yi bile kullanıyor olabiliriz. Kompozisyon API'sinin küçük reaktiflik parçalarını SFC'lerle nasıl bütünleştiririz? Vue 3, sadece bunun için başka bir bölüm sunar: setup . Yeni bölüm, yeni bir yaşam döngüsü yöntemi olarak düşünülebilir (diğer herhangi bir kancadan önce, özellikle de created önce yürütülür).

Geleneksel yaklaşımı Composition API ile entegre eden eksiksiz bir bileşen örneği:

 <template> <input v-model="x" /> <div>Squared: {{ x_squared }}, negative: {{ x_negative }}</div> </template> <script> import { ref, computed } from 'vue'; export default { name: "Demo", computed: { x_negative() { return -this.x; } }, setup() { const x = ref(0); const x_squared = computed(() => x.value * x.value); return {x, x_squared}; } } </script>

Bu örnekten çıkarılması gerekenler:

  • Tüm Composition API kodu şimdi setup . Her işlevsellik için ayrı bir dosya oluşturmak, bu dosyayı bir SFC'ye almak ve setup istenen reaktivite bitlerini döndürmek (bileşenin geri kalanında kullanılabilir kılmak için) isteyebilirsiniz.
  • Yeni ve geleneksel yaklaşımı aynı dosyada karıştırabilirsiniz. x öğesinin bir başvuru olmasına rağmen, şablon kodunda veya bir bileşenin geleneksel bölümlerinde (örneğin, computed ) atıfta bulunulduğunda .value gerektirmediğine dikkat edin.
  • Son olarak, şablonumuzda iki kök DOM düğümümüz olduğuna dikkat edin; Birden fazla kök düğüme sahip olma yeteneği, Vue 3'ün bir başka yeni özelliğidir.

Reaktivite Vue 3'te Daha Etkileyici

Bu makalenin ilk bölümünde, geliştirilmiş kod organizasyonu ve yeniden kullanımı olan Composition API için standart motivasyona değindik. Aslında, yeni API'nin ana satış noktası gücü değil, getirdiği organizasyonel kolaylık: kodu daha net bir şekilde yapılandırma yeteneği. Hepsi bu kadar gibi görünebilir - Kompozisyon API'si, karışımlar gibi halihazırda mevcut olan çözümlerin sınırlamalarından kaçınan bileşenleri uygulamanın bir yolunu sağlar.

Ancak, yeni API'de daha fazlası var. Composition API aslında yalnızca daha iyi organize edilmiş değil, aynı zamanda daha güçlü reaktif sistemler de sağlar. Anahtar bileşen, uygulamaya dinamik olarak reaktivite ekleme yeteneğidir. Önceden, bir bileşeni yüklemeden önce tüm verileri, tüm hesaplanan özellikleri vb. tanımlamak gerekiyordu. Daha sonraki bir aşamada reaktif nesneler eklemek neden faydalı olabilir? Geriye daha karmaşık bir örneğe bakacağız: elektronik tablolar.

Vue 2'de Elektronik Tablo Oluşturma

Microsoft Excel, LibreOffice Calc ve Google Sheets gibi elektronik tablo araçlarının hepsinde bir çeşit reaktivite sistemi vardır. Bu araçlar, kullanıcıya A–Z, AA–ZZ, AAA–ZZZ vb. ile indekslenmiş sütunlar ve sayısal olarak indekslenmiş satırlar içeren bir tablo sunar.

Her hücre düz bir değer veya formül içerebilir. Formül içeren bir hücre, esasen, değerlere veya diğer hesaplanmış özelliklere bağlı olabilen hesaplanmış bir özelliktir. Standart elektronik tablolarla (ve Vue'daki reaktivite sisteminin aksine), bu hesaplanmış özelliklerin kendilerine bağımlı olmalarına bile izin verilir! Bu tür kendi kendine referans, istenen değerin yinelemeli yaklaşımla elde edildiği bazı senaryolarda kullanışlıdır.

Bir hücrenin içeriği değiştiğinde, söz konusu hücreye bağlı olan tüm hücreler bir güncellemeyi tetikleyecektir. Daha fazla değişiklik olursa, daha fazla güncelleme planlanabilir.

Vue ile bir elektronik tablo uygulaması oluşturacak olsaydık, Vue'nin kendi reaktivite sistemini kullanmak ve Vue'yi bir elektronik tablo uygulamasının motoru yapmak için kullanıp kullanamayacağımızı sormak doğal olurdu. Her hücre için, onun ham düzenlenebilir değerini ve buna karşılık gelen hesaplanmış değeri hatırlayabiliriz. Düz bir değerse, hesaplanan değerler ham değeri yansıtır, aksi takdirde hesaplanan değerler düz bir değer yerine yazılan ifadenin (formül) sonucudur.

Vue 2 ile, bir elektronik tabloyu uygulamanın bir yolu, raw_values iki boyutlu bir dizi dizisine ve computed_values (hesaplanmış) iki boyutlu hücre değerleri dizisine sahip olmaktır.

Uygun Vue bileşeni yüklenmeden önce hücre sayısı küçük ve sabitse, bileşen tanımımızda tablonun her hücresi için bir ham ve bir hesaplanmış değere sahip olabiliriz. Böyle bir uygulamanın neden olacağı estetik canavarlığın yanı sıra, derleme zamanında sabit sayıda hücreye sahip bir tablo muhtemelen bir elektronik tablo olarak sayılmaz.

computed_values iki boyutlu diziyle ilgili de sorunlar var. Hesaplanan bir özellik her zaman, bu durumda değerlendirmesi kendisine bağlı olan bir fonksiyondur (bir hücrenin değerinin hesaplanması, genel olarak, diğer bazı değerlerin önceden hesaplanmasını gerektirir). Vue kendine referanslı hesaplanmış özelliklere izin verse bile, tek bir hücrenin güncellenmesi tüm hücrelerin yeniden hesaplanmasına neden olur (bağımlılıklar olup olmadığına bakılmaksızın). Bu son derece verimsiz olacaktır. Bu nedenle, Vue 2 ile ham verilerdeki değişiklikleri tespit etmek için reaktiviteyi kullanabiliriz, ancak reaktivite açısından her şeyin sıfırdan uygulanması gerekir.

Vue 3'te Hesaplanan Değerleri Modelleme

Vue 3 ile her hücre için yeni bir hesaplanmış özellik sunabiliriz. Tablo büyürse, yeni hesaplanmış özellikler sunulur.

A1 ve A2 hücrelerimiz olduğunu ve A2 , değeri 5 olan A1 karesini görüntülemesini istediğimizi varsayalım. Bu durumun bir taslağı:

 let A1 = computed(() => 5); let A2 = computed(() => A1.value * A1.value); console.log(A2.value); // outputs 25

Bir an için bu basit senaryoda kaldığımızı varsayalım. Burada bir sorun var; A1 6 sayısını içerecek şekilde değiştirmek istersek? Diyelim ki şunu yazdık:

 A1 = computed(() => 6); console.log(A2.value); // outputs 25 if we already ran the code above

Bu, A1 yalnızca 5 ila 6 değerini değiştirmedi. A1 değişkeni artık tamamen farklı bir kimliğe sahiptir: 6 sayısına çözümlenen hesaplanmış özellik. Bununla birlikte, A2 değişkeni, A1 değişkeninin eski kimliğindeki değişikliklere hala tepki verir. Bu nedenle, A2 doğrudan A1 atıfta bulunmamalı, bunun yerine bağlamda her zaman mevcut olacak ve bize şu anda A1 ne olduğunu söyleyecek bazı özel nesnelere atıfta bulunmalıdır. Başka bir deyişle, A1 erişmeden önce bir işaretçi gibi bir dolaylılık düzeyine ihtiyacımız var. Javascript'te birinci sınıf varlıklar olarak işaretçiler yoktur, ancak bir tanesini simüle etmek kolaydır. Bir value işaret eden bir pointer sahip olmak istiyorsak, bir pointer = {points_to: value} nesnesi oluşturabiliriz. İşaretçinin yeniden yönlendirilmesi, pointer.points_to atama yapılması ve başvurunun kaldırılması (işaret edilen değere erişim), pointer.points_to değerinin alınması anlamına gelir. Bizim durumumuzda aşağıdaki gibi ilerliyoruz:

 let A1 = reactive({points_to: computed(() => 5)}); let A2 = reactive({points_to: computed(() => A1.points_to * A1.points_to)}); console.log(A2.points_to); // outputs 25

Şimdi 5'i 6 ile değiştirebiliriz.

 A1.points_to = computed(() => 6); console.log(A2.points_to); // outputs 36

Vue'nun Discord sunucusunda, redblobgames kullanıcısı başka bir ilginç yaklaşım önerdi: hesaplanmış değerler kullanmak yerine, normal işlevleri saran referansları kullanın. Bu şekilde, referansın kimliğini değiştirmeden işlevi benzer şekilde değiştirebilir.

Elektronik tablo uygulamamız, bazı iki boyutlu dizilerin anahtarları tarafından atıfta bulunulan hücrelere sahip olacaktır. Bu dizi, ihtiyaç duyduğumuz dolaylılık düzeyini sağlayabilir. Bu nedenle, bizim durumumuzda herhangi bir ek işaretçi simülasyonuna ihtiyaç duymayacağız. Ham ve hesaplanmış değerler arasında ayrım yapmayan bir dizimiz bile olabilir. Her şey hesaplanmış bir değer olabilir:

 const cells = reactive([ computed(() => 5), computed(() => cells[0].value * cells[0].value) ]); cells[0] = computed(() => 6); console.log(cells[1].value); // outputs 36

Ancak, ham değeri bir HTML girdi öğesine bağlayabilmek istediğimizden, ham ve hesaplanmış değerleri gerçekten ayırt etmek istiyoruz. Ayrıca, ham değerler için ayrı bir dizimiz varsa, hesaplanan özelliklerin tanımlarını asla değiştirmemiz gerekmez; ham verilere göre otomatik olarak güncellenirler.

Elektronik Tabloyu Uygulama

Çoğunlukla kendi kendini açıklayan bazı temel tanımlarla başlayalım.

 const rows = ref(30), cols = ref(26); /* if a string codes a number, return the number, else return a string */ const as_number = raw_cell => /^[0-9]+(\.[0-9]+)?$/.test(raw_cell) ? Number.parseFloat(raw_cell) : raw_cell; const make_table = (val = '', _rows = rows.value, _cols = cols.value) => Array(_rows).fill(null).map(() => Array(_cols).fill(val)); const raw_values = reactive(make_table('', rows.value, cols.value)); const computed_values = reactive(make_table(undefined, rows.value, cols.value)); /* a useful metric for debugging: how many times did cell (re)computations occur? */ const calculations = ref(0);

Plan, her computed_values[row][column] aşağıdaki gibi hesaplanmasıdır. raw_values[row][column] = ile başlamıyorsa, raw_values[row][column] . Aksi takdirde, formülü ayrıştırın, JavaScript'e derleyin, derlenen kodu değerlendirin ve değeri döndürün. İşleri kısa tutmak için, formülleri ayrıştırarak biraz hile yapacağız ve burada derleme önbelleği gibi bazı bariz optimizasyonlar yapmayacağız.

Kullanıcıların herhangi bir geçerli JavaScript ifadesini formül olarak girebileceğini varsayacağız. A1, B5 vb. gibi kullanıcı ifadelerinde görünen hücre adlarına yapılan başvuruları, gerçek hücre değerine (hesaplanan) yapılan başvuruyla değiştirebiliriz. Aşağıdaki işlev, hücre adlarına benzeyen dizelerin gerçekten her zaman hücreleri tanımladığını (ve alakasız bazı JavaScript ifadelerinin parçası olmadığını) varsayarak bu işi yapar. Basit olması için, sütun indekslerinin tek bir harften oluştuğunu varsayacağız.

 const letters = Array(26).fill(0) .map((_, i) => String.fromCharCode("A".charCodeAt(0) + i)); const transpile = str => { let cell_replacer = (match, prepend, col, row) => { col = letters.indexOf(col); row = Number.parseInt(row) - 1; return prepend + ` computed_values[${row}][${col}].value `; }; return str.replace(/(^|[^AZ])([AZ])([0-9]+)/g, cell_replacer); };

transpile işlevini kullanarak, JavaScript'in küçük "uzantımızda" hücre referanslarıyla yazılmış ifadelerden saf JavaScript ifadeleri elde edebiliriz.

Sonraki adım, her hücre için hesaplanmış özellikler oluşturmaktır. Bu prosedür, her hücrenin ömrü boyunca bir kez gerçekleşir. İstenen hesaplanmış özellikleri döndürecek bir fabrika yapabiliriz:

 const computed_cell_generator = (i, j) => { const computed_cell = computed(() => { // we don't want Vue to think that the value of a computed_cell depends on the value of `calculations` nextTick(() => ++calculations.value); let raw_cell = raw_values[i][j].trim(); if (!raw_cell || raw_cell[0] != '=') return as_number(raw_cell); let user_code = raw_cell.substring(1); let code = transpile(user_code); try { // the constructor of a Function receives the body of a function as a string let fn = new Function(['computed_values'], `return ${code};`); return fn(computed_values); } catch (e) { return "ERROR"; } }); return computed_cell; }; for (let i = 0; i < rows.value; ++i) for (let j = 0; j < cols.value; ++j) computed_values[i][j] = computed_cell_generator(i, j);

Yukarıdaki kodun tamamını setup metoduna {raw_values, computed_values, rows, cols, letters, calculations} döndürmemiz gerekir.

Aşağıda, temel bir kullanıcı arayüzü ile birlikte tüm bileşeni sunuyoruz.

Kod GitHub'da mevcuttur ve ayrıca canlı demoya da göz atabilirsiniz.

 <template> <div> <div>Calculations: {{ calculations }}</div> <table class="table" border="0"> <tr class="row"> <td></td> <td class="column" v-for="(_, j) in cols" :key="'header' + j" > {{ letters[j] }} </td> </tr> <tr class="row" v-for="(_, i) in rows" :key="i" > <td class="column"> {{ i + 1 }} </td> <td class="column" v-for="(__, j) in cols" :key="i + '-' + j" :class="{ column_selected: active(i, j), column_inactive: !active(i, j), }" @click="activate(i, j)" > <div v-if="active(i, j)"> <input :ref="'input' + i + '-' + j" v-model="raw_values[i][j]" @keydown.enter.prevent="ui_enter()" @keydown.esc="ui_esc()" /> </div> <div v-else v-html="computed_value_formatter(computed_values[i][j].value)"/> </td> </tr> </table> </div> </template> <script> import {ref, reactive, computed, watchEffect, toRefs, nextTick, onUpdated} from "vue"; export default { name: 'App', components: {}, data() { return { ui_editing_i: null, ui_editing_j: null, } }, methods: { get_dom_input(i, j) { return this.$refs['input' + i + '-' + j]; }, activate(i, j) { this.ui_editing_i = i; this.ui_editing_j = j; nextTick(() => this.get_dom_input(i, j).focus()); }, active(i, j) { return this.ui_editing_i === i && this.ui_editing_j === j; }, unselect() { this.ui_editing_i = null; this.ui_editing_j = null; }, computed_value_formatter(str) { if (str === undefined || str === null) return 'none'; return str; }, ui_enter() { if (this.ui_editing_i < this.rows - 1) this.activate(this.ui_editing_i + 1, this.ui_editing_j); else this.unselect(); }, ui_esc() { this.unselect(); }, }, setup() { /*** All the code we wrote above goes here. ***/ return {raw_values, computed_values, rows, cols, letters, calculations}; }, } </script> <style> .table { margin-left: auto; margin-right: auto; margin-top: 1ex; border-collapse: collapse; } .column { box-sizing: border-box; border: 1px lightgray solid; } .column:first-child { background: #f6f6f6; min-width: 3em; } .column:not(:first-child) { min-width: 4em; } .row:first-child { background: #f6f6f6; } #empty_first_cell { background: white; } .column_selected { border: 2px cornflowerblue solid !important; padding: 0px; } .column_selected input, .column_selected input:active, .column_selected input:focus { outline: none; border: none; } </style>

Peki Gerçek Dünya Kullanımı?

Vue 3'ün ayrıştırılmış reaktivite sisteminin sadece daha temiz koda değil, aynı zamanda Vue'nin yeni reaktivite mekanizmasına dayalı daha karmaşık reaktif sistemlere nasıl izin verdiğini gördük. Vue'nun piyasaya sürülmesinden bu yana yaklaşık yedi yıl geçti ve dışavurumculuktaki artış açıkça pek rağbet görmedi.

Elektronik tablo örneği, Vue'nin şu anda neler yapabileceğinin basit bir gösterimidir ve ayrıca canlı demoyu da kontrol edebilirsiniz.

Ancak gerçek bir kelime örneği olarak, biraz niş. Yeni sistem ne tür durumlarda kullanışlı olabilir? İsteğe bağlı tepkime için en belirgin kullanım durumu, karmaşık uygulamalar için performans kazanımlarında olabilir.

Vue 2 ve Vue 3 huni karşılaştırması.

Büyük miktarda veriyle çalışan ön uç uygulamalarda, kötü düşünülmüş tepkiselliği kullanmanın ek yükü performans üzerinde olumsuz bir etkiye sahip olabilir. Şirketin ticari faaliyetlerine ilişkin etkileşimli raporlar üreten bir iş panosu uygulamamız olduğunu varsayalım. Kullanıcı bir zaman aralığı seçebilir ve rapora performans göstergeleri ekleyebilir veya kaldırabilir. Bazı göstergeler, diğer göstergelere bağlı değerleri görüntüleyebilir.

Rapor oluşturmayı uygulamanın bir yolu, monolitik bir yapıdır. Kullanıcı arayüzde bir girdi parametresini değiştirdiğinde, tek bir hesaplanmış özellik, örneğin, report_data güncellenir. Bu hesaplanan özelliğin hesaplanması, kodlanmış bir plana göre gerçekleşir: önce tüm bağımsız performans göstergelerini, ardından yalnızca bu bağımsız göstergelere bağlı olanları hesaplayın, vb.

Daha iyi bir uygulama, raporun bitlerini ayıracak ve bunları bağımsız olarak hesaplayacaktır. Bunun bazı faydaları vardır:

  • Geliştiricinin, sıkıcı ve hataya açık olan bir yürütme planını sabit kodlaması gerekmez. Vue'nin tepkisellik sistemi, bağımlılıkları otomatik olarak algılayacaktır.
  • Dahil edilen veri miktarına bağlı olarak, yalnızca mantıksal olarak değiştirilmiş girdi parametrelerine bağlı olan rapor verilerini güncellediğimiz için önemli performans kazanımları elde edebiliriz.

Vue bileşeni yüklenmeden önce nihai raporun bir parçası olabilecek tüm performans göstergeleri biliniyorsa, önerilen ayrıştırmayı Vue 2 ile bile uygulayabiliriz. genellikle veriye dayalı uygulamalarda geçerlidir) veya harici veri sağlayıcılar varsa, raporun her parçası için isteğe bağlı hesaplanmış özellikler oluşturabiliriz.

Vue 3 sayesinde bu artık sadece mümkün değil, aynı zamanda yapılması da kolay.