web-dev-qa-db-ja.com

Vue jsでパラメーター化された子コンポーネントを変更するときに親コンポーネントが再読み込みされないようにする方法

Securities(子コンポーネント)のリストを含むClientPortfolio(親コンポーネント)がv-data-tableリストにロードされるページがあります。

enter image description here

私が抱えている問題は、リストのセキュリティをクリックするたびにClientPortfolioが完全にリロードされ、リスト全体が更新されて、スクロールと選択したクラスがリセットされるだけでなく、不必要なパフォーマンスオーバーヘッドが発生することです。 Vueのドキュメントを確認しましたが、パラメータがある場合にのみ子コンポーネントを更新する方法は何も指摘されていないようです。ルートが毎回変化するため、親コンポーネントが更新されているようですVueはを知っている(= /// =)知っているサブ(ネストされたルート)のみが変更されているため、セキュリティが選択されているため、子コンポーネントを再ロードするだけでよい

enter image description here

私が得た最も近い答えは https://github.com/vuejs/vue-router/issues/2 で説明されていましたが、これはコードでこれを達成する方法を説明していません。

routes.js:

routes: [
    {
      path: '/client/:clientno/portfolios/:portfolioNo',
      component: ClientPortfolios,
      children: [
        { path: 'security/:securityNo', component: Security }
      ]     
    }, 
  ]

ClientPortfolios.vueのルーターリンク:

 <router-link tag="tr" style="cursor:pointer"
              :to="`/client/${$route.params.clientno}/portfolios/${selectedPortfolioSequenceNo}/security/${props.item.SecurityNo}-${props.item.SequenceNo}`"
              :key="props.item.SecurityNo+props.item.SequenceNo">

            </router-link>

ClientPortfolios.vueのルータービュー(セキュリティコンポーネント用):

<v-flex xs10 ml-2>
      <v-layout>
          <router-view :key="$route.fullPath"></router-view>
      </v-layout>
    </v-flex>

親がリロードされないようにする方法についてのヒントはありがたいです。

編集:問題に近づこうとすると、セキュリティを変更するたびに、ClientPortfoliosの「キー」属性が(Vueデバッグウィンドウに示されているように)変更される)ことに気付きます。理由はありますか?子ではありませんが、ClientPortfoliosコンポーネントにキーを割り当てる方法はありますか?または、別の証券に移動するときにキーを更新しない方法はありますか?

更新:完全なコード

ClientPortfolios.vue

<template>
  <v-layout row fill-height>
    <v-flex xs2>
      <v-layout column class="ma-0 pa-0 elevation-1">
        <v-flex>
          <v-select v-model="selectedPortfolioSequenceNo" :items="clientPortfolios" box label="Portfolio"
            item-text="SequenceNo" item-value="SequenceNo" v-on:change="changePortfolio">
          </v-select>
        </v-flex>
        <v-data-table disable-initial-sort :items="securities" item-key="Id" hide-headers hide-actions
          style="overflow-y: auto;display:block;height: calc(100vh - 135px);">
          <template slot="items" slot-scope="props">
            <router-link tag="tr" style="cursor:pointer"
              :to="{ name: 'Security', params: { securityNo: props.item.SecurityNo+'-'+props.item.SequenceNo } }"
              >
            </router-link>

          </template>
          <template v-slot:no-data>
            <v-flex class="text-xs-center">
              No securities found
            </v-flex>
          </template>
        </v-data-table>
      </v-layout>
    </v-flex>

    <v-flex xs10 ml-2>
      <v-layout>
        <keep-alive>
          <router-view></router-view>
        </keep-alive>
      </v-layout>
    </v-flex>
  </v-layout>

</template>
<script>
  import Security from '@/components/Security'

  export default {
    components: {

      security: Security
    },
    data () {
      return {
        portfoliosLoading: false,
        selectedPortfolioSequenceNo: this.$route.params.portfolioNo,
        selectedPortfolio: null,
        securityNo: this.$route.params.securityNo
      }
    },
    computed: {
      clientPortfolios () {
        return this.$store.state.ClientPortfolios
      },
      securities () {
        if (this.clientPortfolios == null || this.clientPortfolios.length < 1) {
          return []
        }
        let self = this
        this.selectedPortfolio = global.jQuery.grep(this.clientPortfolios, function (portfolio, i) {
          return portfolio.SequenceNo === self.selectedPortfolioSequenceNo
        })[0]

        return this.selectedPortfolio.Securities
      }
    },
    mounted () {
      this.getClientPortfolios()
    },
    activated () {
    },
    methods: {
      changePortfolio () {
        this.$router.Push({
          path: '/client/' + this.$route.params.clientno + '/portfolios/' + this.selectedPortfolioSequenceNo
        })
      },
      getClientPortfolios: function () {
        this.portfoliosLoading = true
        let self = this
        this.$store.dispatch('getClientPortfolios', {
          clientNo: this.$route.params.clientno
        }).then(function (serverResponse) {
          self.portfoliosLoading = false
        })
      }
    }
  }
</script>

Security.vue

<template>
  <v-flex>
    <v-layout class="screen-header">
      <v-flex class="screen-title">Security Details </v-flex>

    </v-layout>
    <v-divider></v-divider>
    <v-layout align-center justify-space-between row class="contents-placeholder" mb-3 pa-2>
      <v-layout column>
        <v-flex class="form-group" id="security-portfolio-selector">
          <label class="screen-label">Sequence</label>
          <span class="screen-value">{{security.SequenceNo}}</span>
        </v-flex>
        <v-flex class="form-group">
          <label class="screen-label">Security</label>
          <span class="screen-value">{{security.SecurityNo}}-{{security.SequenceNo}}</span>
        </v-flex>

        <v-flex class="form-group">
          <label class="screen-label">Status</label>
          <span class="screen-value-code" v-if="security.Status !== ''">{{security.Status}}</span>
        </v-flex>
      </v-layout>

    </v-layout>

  </v-flex>

</template>
<script>
  export default {
    props: ['securityNo'],
    data () {
      return {
        clientNo: this.$route.params.clientno,
        securityDetailsLoading: false
      }
    },
    computed: {
      security () {
        return this.$store.state.SecurityDetails
      }
    },

    created () {
      if (this.securityNo.length > 1) {
        this.getSecurityDetails()
      }
    },

    methods: {
      getSecurityDetails: function () {
        let self = this
        this.securityDetailsLoading = true

        this.$store.dispatch('getSecurityDetails', {
          securityNo: this.securityNo,
          clientNo: this.clientNo

        }).then(function (serverResponse) {
          self.securityDetailsLoading = false
        })
      }
    }
  }
</script>

router.js

const router = new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      component: Dashboard
    },
    {
      path: '/client/:clientno/details',
      component: Client,
      props: true
    },

    {
      path: '/client/:clientno/portfolios/:portfolioNo',
      component: ClientPortfolios,
      name: 'ClientPortfolios',
      children: [
        { path: 'security/:securityNo',
          component: Security,
          name: 'Security'
        }
      ]
    }
  ]
})

[〜#〜]更新[〜#〜]

しばらくしてこれを更新するために、私はようやく問題が何であるかを見つけました。これは@matpieが他の場所で示したものです。私のApp.vueが:keyが追加されている原因であることがわかりましたアプリケーションのルート:<router-view :key="$route.fullPath" />これは私がどこかから使用したテンプレートでしたが、「機能している」ので確認する必要はありませんでした。キーを削除すると、すべてが正常に機能し、マッピーの回答が受け入れられたことを示します。

16
Maya

コンポーネントの再読み込みを防ぐことが、Vue.jsのデフォルトの動作です。 Vueの反応システムは、プロパティの依存関係を自動的にマッピングし、DOMが最新であることを確認するために最小限の作業のみを実行します。

:key属性はどこでも、キーが一致する場合、この要素またはコンポーネントがonlyに一致する必要があることをVue.jsに伝えています。キーが一致しない場合、古いキーは破棄され、新しいキーが作成されます。

データオブジェクトのルートパラメータ(Security.vue)。これらはルートパラメータが変更されても更新されません。それらを常に最新の状態に保つために、それらを計算されたプロパティにプルする必要があります。

export default {
  computed: {
    clientNo: (vm) => vm.$route.params.clientno,
  }
}

これにより、Vueがこのコンポーネントインスタンスを再利用するかどうかに関係なく、clientNoは常にルーターで検出されたものと一致します。他の副作用を実行する必要がある場合clientNoが変わったら、ウォッチャーを追加できます:

vm.$watch("clientNo", (clientNo) => { /* ... */ })
5
matpie

セキュリティコンポーネントのローカル登録を削除してから、もう一度確認してください。これはvueルーター自体によって処理されているため、必要ありません。

components: { // delete this code

      security: Security
    },
0
fullmetal