Реактивность Vue.js и Object.defineProperty с TypeScript

Я создаю класс в TypeScript для обработки отправки формы и ошибок сервера:

export default class Form<Model> {
    private readonly original: Model
    private changes: Partial<Model>

    constructor(data: Model) {
        this.original = data
        Object.keys(this.original).forEach(key => this.initialiseData(key))
    }

    private initialiseData(key) {
        Object.defineProperty(this, key, {
            get: () => this.data[key],
            set: (value) => this.changes[key] = value
        }
    }

    get data(): Model {
        return Object.assign({}, this.original, this.changes)
    }

    post(url: string) {
        // post logic
    }
}

Это будет использоваться в моих компонентах Vue следующим образом:

import { Component, Vue } from 'vue-property-decorator'
import Form from '~/src/vform'

interface LoginForm {
    email: string
    password: string
}

@Component
export default class LoginView extends Vue {
    form: Form<LoginForm> = new Form<LoginForm>({
        email: '',
        password: ''
    })

    async submit() {
        await this.form.post('/auth/login')
    }
}

Это работает, функционально, я могу заполнить форму и отправить данные на сервер. У меня проблема с реактивностью в Vue.js. Поскольку свойства не существуют в классе Form, данные не передаются в v-model, они обновляются внутри формы только после их изменения.

Это не проблема, если только я не показываю данные на экране из формы. Я могу смириться с этим пока, но мне было интересно, есть ли способ заставить Vue распознавать реактивные свойства в моем классе Form, или есть ли лучший способ добиться этой функциональности без ущерба для системы типов.

Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
1
0
990
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Что ж, ваша работа намного выше, чем у vuejs. Vuejs работает с реактивными данными с Object.defineProperty в установщике для повторного рендеринга, однако вы предоставляете объект, который определил свои свойства, которые не настраиваются и не смогут запускать реактивную систему vuejs.

Чтобы это работало:

export default class Form<Model> {

    initialiseData(key) {
        Object.defineProperty(this, key, {
            get: () => this.data[key],
            set: (value) => {
                this.changes[key] = value
                this.onChange(key, value)
            },
        })
    }

    onChange(key, value) {}

}
import _Form from '~/src/vform'

@Component
export default class LoginView extends Vue {
    form: any = {}

    // Lifecycle hook
    mounted() {
        const vm = this
        class Form extends _Form {
          onChange() {
              vm.$forceUpdate()
          }
        }
        const form = new Form({
            email: '',
            password: ''
        })
        this.$set('form', form)
    }
}

Обратите внимание на vm.$forceUpdate, который будет уведомлять vuejs о повторном рендеринге при изменении свойств вашей формы.

Другие вопросы по теме