Почему проп не реагирует на динамический компонент? - PullRequest
0 голосов
/ 04 июля 2019

У меня динамический компонент, внедряемый в слот другого, и я передаю ему объект props. Но когда я обновляю данные (массив), которые были связаны с реквизитом (dataT: this.tableData), этот реквизит не обновляется внутри компонента.

Кажется, что я имею дело с двумя разными объектами, но массив был передан по ссылке, не так ли?

Это основной компонент


    <template>
       <Button @click="addWindows"></Button>
       <Window v-for="window in windows" :key="window.id">
          <component :is="window.name" v-bind="window.props" @onDeleteRow="handleDeleteRow"></component>    
       </Window>
    </template>


    <script>
        export default{
           data(){
              return{
                 windows:[],
                 tableData:[
                    {
                       id: '0',
                       name: 'dog'
                    },
                    {
                       id: '1',
                       name: 'cow'
                    },
                    {
                       id: '2',
                       name: 'cat'
                    }
                 ]
              }
           },  
           methods:{
              addWindows(){
                 this.windows = [
                 {
                    id: 0,
                    name: 'Component1',
                    props: {
                       dataT: this.tableData
                    }
                 }, 
                 {
                    id: 1,
                    name: 'Component2',
                    props: {}
                 }];
              },
              handleDeleteRow(id){
                 this.tableData = this.tableData.filter(r => r.id != id);
              }
           }
        }
    </script>

Я ожидаю обновления dataT prop в Component1 при изменении this.tableData в главном компоненте.

Ответы [ 2 ]

2 голосов
/ 04 июля 2019

Оригинальный ответ на основе более ранней версии вопроса

Если вы сделаете windows вычисляемое свойство, оно может зависеть от tableData:

export default {
  data() {
    return {
      tableData: [
        {
          id: '0',
          name: 'dog'
        },
        {
          id: '1',
          name: 'cow'
        },
        {
          id: '2',
          name: 'cat'
        }
      ]
    }
  },
  computed: {
    windows () {
      return [
        {
          id: 0,
          name: 'Component1',
          props: {
            dataT: this.tableData
          }
        }, {
          id: 1,
          name: 'Component2',
          props: {}
        }
      ]
    }
  }
}

Если вы не можетесделайте все это вычисляемым свойством, например, потому что вам нужно иметь возможность изменить его, затем сохраните его как data и просто используйте вычисленное свойство для создания массива, необходимого в вашем шаблоне.В этом случае вычисляемое свойство будет просто объединять различные части данных в правильную форму.

В исходном коде строка dataT: this.tableData не будет работать, поскольку this.tableData еще не существуетэто будет просто undefined.Здесь нет ленивых вычислений, нужно разрешить правильный объект в том месте, где он попадает в эту строку.

Даже если бы ему удалось получить доступ к правильному объекту, это не помогло бы, потому что в handleDeleteRowВы переназначаете tableData, чтобы указать на другой объект.Передача «по ссылке» не имеет ничего общего с именем, которое вы используете для идентификации объекта, это относится к ссылке в памяти.

Кстати, v-on также поддерживает синтаксис объекта, как и v-bind,так что вы можете сделать onDeleteRow необязательным аналогичным образом.

Обновление на основе отредактированного вопроса

Когда вы пишете это в addWindows:

props: {
    dataT: this.tableData
}

Этоназначит current значение this.tableData для dataT.Это текущее значение будет массивом, и так как массивы являются ссылочными типами, любые изменения, внесенные в этот массив, будут применяться независимо от того, какой идентификатор используется для ссылки на него.

Однако эта строка ...

this.tableData = this.tableData.filter(r => r.id != id);

... не изменяет этот массив.Вместо этого он присваивает совершенно новый массив this.tableData.Это не повлияет на массив, на который ссылается dataT, который не изменился.

Существует несколько способов решения этой проблемы, включая использование вычисляемого свойства.Однако получатель свойства может обеспечить удобную ловкость рук:

addWindows () {
  const vm = this;

  this.windows = [
    {
      id: 0,
      name: 'Component1',
      props: {
        get dataT () {
          return vm.tableData
        }
      }
    },
    {
      id: 1,
      name: 'Component2',
      props: {}
    }
  ];
}

Это всегда будет иметь текущее значение tableData.Реакционная способность Vue должна быть в порядке с этим дополнительным косвенным указанием, она просто считает, что это эквивалентно прямому доступу к tableData.

1 голос
/ 04 июля 2019

TL; DR

Проблема связана с вашей привязкой.Используйте следующее:

<component 
    :is="window.name"
    :dataT="window.props.dataT"
    @onDeleteRow="handleDeleteRow">
</component>

Объяснение

атрибут v-bind указывает, какой реквизит связан с каким значением (или ссылкой).В вашем случае вы не указали, какие значения вы привязываете к каким реквизитам, поэтому реквизиты компонента не были связаны должным образом.

...