Vue 2 Aktualizácia Vlastnosti na Objekt v Pole z Vnorený Komponent

0

Otázka

Pracovala som na Vue 2 projekt na chvíľu, a pri aktualizácii našich linting požiadavky, ktoré som objavil, že sme mali prop mutácie chyby v mnohých našich dieťa komponentov. V našom projekte sme sa prejsť singleton objekt ako prop mnohých komponentov a boli pôvodne aktualizácia objekt priamo od dieťaťa komponentov. Vue sa zdá, že naznačujú, pomocou v-bind.sync funkcia na aktualizáciu props od detskej zložky (alebo pomocou rovnocenných v-bind a v-on). Tento, však, nie je vyriešenie problému prop modifikácia od vnorené komponentov v poli.

Trvať to (pseudo)kód pre príklad, ktorý používa prop mutácia:

Poznámka: Predpokladajme const sharedObject: { arrayElements: Array<{ isSelected: boolean }> } = ...

Stránky.vue

<template>
  ...
  <Component1 :input1="sharedObject" />
  ...
</template>

Component1.vue

<template>
  ...
  <template v-for="elem in sharedObject.arrayElements">
    <Component2 :input2="elem" />
  </template>
  ...
</template>

Component2.vue

<template>
  ...
  <q-btn @click="input2.isSelected = !input2.isSelected"></q-btn>
  ...
</template>

Aký je správny spôsob, ako aktualizovať majetku ako input2.isSelected z vnorených komponentov v Vue 2? Všetky prístupy ja som myslel, že sú chybné.

Chybné Prístupy

Som veriť , že by sme chceli bublina, ktorá input2.isSelected bol upravený v Component2 na Page.vueavšak, zdá sa, že buď viesť k chaotický kód alebo nepríjemný pocit, že sme len potláča linting chyby v kruhový objazd na ceste.


Na preukázanie "chaotický kód" prístup, uvedomíme si, že Page.vue nevie index z elem v sharedObject.arrayElements. Preto by sme potrebovali na vyžarovanie objektu Page.vue z Component1 ktorá obsahuje stav input2.isSelected ako aj index elem v sharedObject.arrayElements. Toto sa chaotický rýchlo. Čo o príklad, kde máme:

Component1.vue

<template>
  ...
  <template v-for="elem in sharedObject.arrayElements">
    <template v-for="elem2 in elem.arrayElements">
       <Component2 :input2="elem2" />
    </template>
  </template>
  ...
</template>

v tomto prípade, potom by sme mohli musieť prejsť up 2 indexy! Nezdá sa, ako udržateľné riešenie mňa.


Alternatívne, že som si myslel ze je callback funkcie (prešiel ako prop prostredníctvom komponentu hierarchie), ktorá berie ako vstupný prvok chceme aktualizovať a objekt, ktorý obsahuje vlastnosti, ktoré chceme aktualizácie (pomocou Object.assign).

To je pre mňa veľmi nepríjemný, pretože neviem, skutočný dôvod, prečo nemôžeme aktualizácia pass-o-odkaz prop z dieťa komponentu. Mne sa to zdá ako je to len objazde spôsob aktualizácii prešiel z Component2 bez linter si všímať. Ak tam nejaké kúzla zmene, ktorá sa stane rekvizity, keď sú odovzdávané dieťa komponenty, potom iste absolvovanie predmetu, ktorý som dostal v Component2 na callback funkcie a úpravy sa v nadradený komponent by v podstate len aktualizovať prop v detskej zložky, ale zložitejšie.

Aký je správny spôsob, ako sa blíži tento problém v Vue 2?

1

Najlepšiu odpoveď

3

Veľmi dobrá otázka a analýza súčasného stavu to dlhodobý problém v Vue ekosystému.

Áno, úprava "hodnota typu" rekvizity od dieťaťa je problém, ako ho vytvorí runtime otázky (rodič prepis zmeny, keď sa opätovne stala), a tak Vue generuje chyba v režime runtime keď sa to stane...

Zmena majetku objektu prešiel ako prop je OK od "kód funguje" POV. Bohužiaľ, tam sú niektoré vplyvné osoby v spoločenstve s názoru (a mnohí, ktorí slepo nasledovať ich), že je to anti-vzor. Nesúhlasím s tým a zdvihol moje argumenty počet krát (napríklad tu). Ste popísané dôvody, veľmi dobre - je to len vytvára zbytočnú zložitosť/štandardný kód...

Tak, čo máte čo do činenia s je naozaj len linting pravidlo (vue/č-mutating-rekvizity). Tam je to pretrvávajúci problém/diskusie , ktoré navrhuje možnosť konfigurácie, ktoré by sa malo umožniť, uľahčiť prísnosť pravidla s mnohými dobré argumenty, ale dostane veľmi malá pozornosť od skutočných správcov (pokojne zvýšiť svoj hlas tam príliš)

Pre teraz, čo môžete urobiť, je:

  1. Vypnúť pravidlo (zďaleka dokonalá, ale našťastie vďaka Vue runtime chyba, ktorú môžete chytiť skutočnú nesprávne prípadoch počas vývoja v pohode)
  2. Akceptovať realitu a použitie postupov

Riešenie - použiť globálne štátu (uložiť ako Vuex alebo Pinia)

Poznámka: Pinia sa uprednostňuje ako ďalšia verzia Vuex bude mať rovnaké API

Základná myšlienka je, aby miesto sharedObject v obchode a používať rekvizity iba na navigáciu dieťa komponenty na pravej objekt - v prípade Component2 dostane index podľa prop a vybrať správny prvok z obchodu pomocou it.

Obchody sú skvelé pre zdieľanie globálny štát, ale používa sa len na prekonanie linting pravidlo je zlé. Tiež výsledkom je, že komponenty sú spolu do obchodu, teda obe opätovnú využiteľnosť trpí a testovanie je ťažšie

Riešenie - udalosti

Áno, to je možné vytvoriť neporiadok a veľa štandardný kód pomocou iba udalosti (najmä ak ste hniezdo komponenty viac ako 2 úrovne), ale existujú spôsoby, ako robiť veci, ktoré sú čistejšie.

Napríklad vo vašom prípade Component2 nemusí vedieť, index ako môžete zvládnuť prípade, ako je tento

// Component1
<template>
  ...
   <template v-for="elem in sharedObject.arrayElements">
    <template v-for="(elem2, index) in elem.arrayElements">
       <Component2 :input2="elem2" @update="updateElement($event, index)" />
    </template>
  </template>
  ...
</template>

Vo vašom prípade, Component2 rukoväte zmeniť len jedného boolean majetok, takže $event môžu byť jednoduché, boolean. Ak existuje viac ako jednu vlastnosť, ktorú chcete zmeniť vnútri Component2, $event môže byť objekt a môžete použiť objekt šíriť syntax "zjednodušiť" na Component2 (pomocou jedného udalosť, namiesto toho, viac - jeden pre každú vlastnosť)

// Component2
<template>
  ...
  <input v-model="someText" type="text">
  <q-btn @click="updateInput('isSelected', !input2.isSelected)"></q-btn>
  ...
</template>
<script>
export default {
  props: ['input2'],
  computed: {
    someText: {
      get() { return this.input2.someText },
      set(newVal) { updateInput('someText', newVal) }
    }
  },
  methods: {
    updateInput(propName, newValue) {
      const updated = { ...this.input2 } // make a copy of input2 object
      updated[propName] = newValue  // change selected property

      this.$emit('update', updated) // send updated object to parent
    }
  }
}
</script>

Dobre...ja radšej len vypnúť pravidlo a nastaviť niektoré jasné konvencie pomenovania na označenie, že komponent je zodpovedný za zmenu je vstup...

Upozorňujeme, že existujú aj iné spôsoby, ako pomocou this.$parent, inject\provide alebo udalosť autobus, ale tie sú naozaj zlé

2021-11-24 09:42:19

V iných jazykoch

Táto stránka je v iných jazykoch

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................