programing

VueJ는 컴포넌트에서 목록을 다시 렌더링하지 않음

firstcheck 2022. 8. 8. 15:32
반응형

VueJ는 컴포넌트에서 목록을 다시 렌더링하지 않음

vuex에서 "v-for"를 통해 어레이를 렌더링하려고 합니다.

"Player-Card" 컴포넌트는 렌더링되지 않습니다.그러나 "td" 솔루션은 올바르게 작동합니다.

JSFiddle의 예

HTML:

    <div id="app">
      <button v-on:click="moveItem">
        Move Item
      </button>

      <table cellspacing="2" border="1" cellpadding="5">
        <tr>
          <td v-for="(item, item_idx) in getItems" v-bind:key="item.col">{{ (item.card)? item.card.name : 'none' }}</td>
        </tr>
        <tr>
          <player-card v-for="(item, item_idx) in getItems" v-bind:key="item.col" v-bind:item="item"></player-card>
        </tr>
      </table>
      <br/>
      <p>{{msg}}</p>
    </div>

스토어:

    const store = new Vuex.Store({
      state: {
        items: [{ col: 0, row: 0 },
                { col: 1, row: 0 },
                { col: 2, row: 0, card: { name: "hello" } } ]
      },
      getters: {
        getterItems: state => { return state.items; }
      },

      mutations: {
        MOVE_ITEM: state => {
          state.items[0].card = state.items[2].card;
          delete state.items[2].card;
          state.message = JSON.stringify(state.items);
        }
      }

    });

컴포넌트:

    Vue.component('player-card', {
      props: {
        item: {
          type: Object,
          required: true
        }
      },
      template: '<td>{{ (item.card)? item.card.name : "none" }}</td>'
    });

앱:

    new Vue({
      el: '#app',
      store,
      data: function() {
        return {
          msg: ''
        }
      },
      computed: {
        getItems() { return this.$store.getters.getterItems; }
      },
      mounted: function() { 
        this.msg = JSON.stringify(this.getItems); 
      },
      methods: {
        moveItem() {
          this.$store.commit('MOVE_ITEM');
          this.msg = JSON.stringify(this.getItems);
        }
      }
    });

나는 이미 많은 해결책을 시도했지만, 간단한 해결책을 찾지 못했다.누군가 다른 아키텍처 솔루션을 제안할 수도 있습니다.

다음 행만 변경하면 됩니다.

<player-card v-for="(item, item_idx) in getItems" v-bind:key="item.col" v-bind:item="item"></player-card>

다음과 같이 입력합니다.

<td is="player-card" v-for="(item, item_idx) in getItems" v-bind:key="item.col" v-bind:item="item"></td>

이것은 템플릿이 DOM에서 지정되어 있기 때문에 필요합니다.브라우저는 Vue가 템플릿 마크업에 접근하기 전에 템플릿 마크업을 해석합니다.HTML 구문 분석 규칙에서는 특정 요소만 의 직계 하위 요소가 될 수 있습니다.<tr>기타 요소는 모두 에서 꺼냅니다.<table>Vue가 템플릿을 해석하기 위해 올 때까지<player-card>요소는 이미 외부로 이동되어 있을 것입니다.<table>.

템플릿을 지정하기 위해 다른 방법 중 하나를 사용해도 문제가 되지 않습니다.

이 문제를 해결하려면is속성을 지정하여 태그 이름 대신 구성 요소를 지정합니다.

이에 대해서는 다음 문서를 참조하십시오.

https://vuejs.org/v2/guide/components.html#DOM-Template-Parsing-Caveats

특수 속성을 사용하여 부과된 요소 구조를 회피해야 합니다.<tr>예기하다<td>어릴 적에 하지만 얻는 것<player-card>(사전 준비 완료).또, 어레이를 뮤트 하는 방법에 의해서, 반응성의 문제가 발생하고 있습니다.거스름돈을 고려하세요.

const store = new Vuex.Store({
  state: {
    items: [{
        col: 0,
        row: 0
      },
      {
        col: 1,
        row: 0
      },
      {
        col: 2,
        row: 0,
        card: {
          name: "hello"
        }
      }
    ]
  },
  getters: {
    getterItems: state => {
      return state.items;
    }
  },

  mutations: {
    MOVE_ITEM: state => {
      // Move the last element to the front
      state.items = [
        ...state.items.slice(-1),
        ...state.items.slice(0, -1)
      ];
      state.message = JSON.stringify(state.items);
    }
  }

});

Vue.component('player-card', {
  props: {
    item: {
      type: Object,
      required: true
    }
  },
  template: '<td>{{ (item.card)? item.card.name : "none" }}</td>'
});

new Vue({
  el: '#app',
  store,
  data: function() {
    return {
      msg: ''
    }
  },
  computed: {
    getItems() {
      return this.$store.getters.getterItems;
    }
  },
  mounted: function() {
    this.msg = JSON.stringify(this.getItems);
  },
  methods: {
    moveItem() {
      this.$store.commit('MOVE_ITEM');
      this.msg = JSON.stringify(this.getItems);
    }
  }
});
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>

<div id="app">
  <button v-on:click="moveItem">
        Move Item
      </button>

  <table cellspacing="2" border="1" cellpadding="5">
    <tr>
      <td v-for="(item, item_idx) in getItems" v-bind:key="item.col">{{ (item.card)? item.card.name : 'none' }}</td>
    </tr>
    <tr>
      <td is="player-card" v-for="(item, item_idx) in getItems" v-bind:key="item.col" v-bind:item="item"></td>
    </tr>
  </table>
  <br/>
  <p>{{msg}}</p>
</div>

또, vuex의 어레이를 갱신하는 문제도 있었습니다.

'공통 초보자 고차'에 대해서

mutations: {
MOVE_ITEM: state => {
  // Move card
  state.items[0].card = state.items[2].card;
  delete state.items[2].card;

  // Simple deep array cloning
  state.items = JSON.parse(JSON.stringify(state.items));

  state.message = JSON.stringify(state.items);
}}

갱신된 JSFiddle

여러분, 정말 감사합니다.

언급URL : https://stackoverflow.com/questions/57275968/vuejs-does-not-rerender-list-from-components

반응형