Vue — Динамические свойства из внешнего класса TypeScript не являются реактивными

#javascript #typescript #vue.js

#javascript #typescript #vue.js

Вопрос:

У меня небольшая проблема, я создал пакет для управления формами, все работало правильно, пока мне не понадобилось создать динамическую форму на основе ответа API.

Вот пакет: https://github.com/nulvem/js-form

Он может быть установлен с помощью npm:

 npm install @nulvem/js-form
 

Вот мой компонент Vue, вызывающий Form класс:

 <script>
import {Form} from '@nulvem/js-form'

export default {
  data() {
    return {
      form: new Form({
        template: {
          value: null,
          validation: {
            rules: 'required',
            messages: {
              required: 'You must select the type of report'
            }
          }
        }
      })
    }
  },
  mounted() {
    this.form.template = 'random-id'

    // These data will be obtained from an API
    let fields = [
      'start_date',
      'end_date',
      'wallets',
    ]

    fields.forEach((field) => {
      let fieldData = {
        value: null,
        validation: {
          rules: 'required',
          messages: {
            required: `You must enter the field ${field.description}`
          }
        }
      }

      this.form.$addField(field, fieldData)
    })

    // Here we can only see the getter/setter of the template property that was passed when instantiating the Form class
    console.log(this.form)
  }
}
</script>
 

Проблема в том: Поля, которые я передал форме во время создания new Form ({...}) экземпляра, являются реактивными, поскольку, когда я добавляю новые поля, вызывая this.form.$AddField() функцию, поля не становятся реактивными.

Самое смешное, что construct из Form класса вызывается вызываемая функция this.form.$AddFields() , которая вызывает this.form.$AddField() функцию несколько раз.

Почему он работает внутри конструктора и не работает при вызове separated? Как исправить эту проблему?

Есть идеи, что может происходить? Это сводит меня с ума, я пытался найти проблему в течение нескольких часов, и я не могу ее найти.

Редактировать

В качестве быстрого исправления мы вносим изменения в пакет, в котором можно передавать Form экземпляр в качестве третьего параметра $addFields функции, поэтому атрибуты являются реактивными, однако мы хотели бы, чтобы это работало без необходимости передавать этот параметр.

Комментарии:

1. Vue 2 не обнаруживает добавление / удаление свойств объекта, поэтому вы должны использовать Vue.set() / Vue.delete() для этого. Если вы только инициализируете форму mounted() со всеми полями из API, я бы установил form = new Form() mounted() ее, как только у вас будут доступны все поля. Тогда вам не нужно было бы передавать контекст.

2. Вы должны заменить form экземпляр на новый, содержащий поля. Я бы сказал, что самый простой способ — просто поместить null заполнитель data: () => { form: null } и установить экземпляр класса form, когда у вас есть все поля из API. Что означает реактивность Vue: все свойства заменяются на геттеры / сеттеры, но это происходит только на верхнем уровне, а не для каждого отдельного вложенного prop. Если вы не замените form Vue, он не узнает об изменении. И Vue.set() делает именно это. Он заменяет экземпляр в prop.

Ответ №1:

VueJS теряют реактивность свойств, которые добавляются к вам data после рендеринга. Подробнее об этом можно прочитать здесь: https://br.vuejs.org/v2/guide/reactivity.html .

Быстрый способ попытаться решить эту проблему — добавлять this.$forceUpdate() каждый раз, когда вы добавляете новое свойство, но это также может вызвать другие проблемы в зависимости от вашего контекста.

Или вы можете попробовать использовать Vue.set() метод вместо вашего $addField метода. Вы можете прочитать больше по той же ссылке выше.

Комментарии:

1. Мне нужно позвонить $addField() , потому что это разрешит мои правила проверки и сообщения внутри класса

2. В любом случае, я думаю, вы можете попробовать использовать Vue.set , а также добавить свойства в свой form .

Ответ №2:

удалите контекст и измените эту строку на реактивность:

 this.$initialValues[field] = fieldDeclaration.value;
 

=>>>

 this.$initialValues[field] = fieldDeclaration.value;
this.$initialValues = Object.assign({}, this.$initialValues);
 

Комментарии:

1. $initialValus является реактивным, проблема заключается в доступе к itens в экземпляре формы