ProtoModel
Абстрактный базовый класс для создания реактивных моделей с управлением действиями.
abstract class ProtoModelСтатические методы
createModel
ProtoModel.createModel<Target>(protoModel: Target): Model<Target>Оборачивает экземпляр ProtoModel в прокси для обработки геттеров действий и возврата экземпляров Action вместо оригинальных методов.
Параметры:
protoModelTarget- Экземпляр класса, расширяющего ProtoModel
Возвращает:
Model<Target> Экземпляр модели, обёрнутый прокси
Выбрасывает:
TypeError если аргумент не является экземпляром ProtoModel
Пример:
class TestModel extends ProtoModel {
protected _value = ''
static customConstructor(value: string): Model<TestModel> {
const protoModel = new TestModel()
protoModel._value = value
return ProtoModel.createModel(protoModel)
}
}
const model = TestModel.customConstructor('init value')model
ProtoModel.model<T, Args>(...args: Args): Model<T>Статический фабричный метод для создания экземпляра модели. Может быть вызван на классе, расширяющем ProtoModel. Копирует сигнатуру конструктора класса.
Параметры:
...argsArgs- Аргументы для конструктора модели, совпадают с аргументами конструктора класса.
Возвращает:
Model<T> Экземпляр модели
Выбрасывает:
Error если вызван напрямую на ProtoModel (абстрактный класс)
Пример:
interface Api {
fetchUser: () => Promise<void>
patch: () => Promise<void>
}
class UserModel extends ProtoModel {
constructor(private api: Api) {
super()
}
}
const user = UserModel.model({ fetchUser, patch })Свойства экземпляра
hasPendingActions
readonly hasPendingActions: booleanВозвращает true, если какое-либо действие в модели находится в состоянии pending.
hasActionWithError
readonly hasActionWithError: booleanВозвращает true, если какое-либо действие в модели находится в состоянии error.
Защищённые методы
watch
watch(...args: unknown[]): WatchStopHandleРегистрирует наблюдатель в области эффектов модели. Использует watch или watchEffect из Vue.
Параметры:
...argsunknown[]- Аргументы дляwatch/watchEffectиз Vue- Если один аргумент: обрабатывается как
watchEffect - Если несколько аргументов: обрабатывается как
watch
- Если один аргумент: обрабатывается как
Возвращает:
WatchStopHandle Функцию для остановки наблюдателя
Выбрасывает:
Error если аргументы не предоставлены
Ограничения:
- Не может использоваться с нереактивными свойствами
thisво внутреннем контексте не является shallow reactive- Используйте
refилиcomputedдля реактивных свойств
Пример:
class TestModel extends ProtoModel {
protected _count = ref(0)
constructor() {
super()
this.watch(
() => this._count.value,
(value) => console.log(value)
)
}
}computed
computed<T>(getter: ComputedGetter<T>, debugOptions?: DebuggerOptions): ComputedRef<T>Создаёт вычисляемое свойство в области эффектов модели.
Параметры:
getterComputedGetter<T>- Функция-геттер для вычисляемого свойстваdebugOptionsDebuggerOptions(опционально) - Опциональные опции отладки для computed из Vue
Возвращает:
ComputedRef<T> Экземпляр ComputedRef
Пример:
class TestModel extends ProtoModel {
protected _firstName = ref('John')
protected _lastName = ref('Doe')
get fullName() {
return this.computed(() =>
`${this._firstName.value} ${this._lastName.value}`
)
}
}action
action(originalMethod: OriginalMethod | OriginalMethodWrapper): ActionLike<this>Получает экземпляр Action по обёрнутому оригинальному методу или создаёт новый экземпляр Action.
Параметры:
originalMethodOriginalMethod | OriginalMethodWrapper- Оригинальный метод или обёртка метода с декоратором action
Возвращает:
ActionLike<this> Экземпляр Action
Выбрасывает:
ActionInternalError если декоратор action не применён
Использование:
- Внешний контекст: вызывается неявно при доступе к свойствам действий в модели
- Внутренний контекст: должен вызываться явно как
this.action(this.someAction)
Пример:
class TestModel extends ProtoModel {
@action async testAction(): Promise<void> {
return Promise.resolve()
}
async otherAction(): Promise<void> {
// Во внутреннем контексте используйте this.action()
if (this.action(this.testAction).isPending) {
console.log('testAction is pending')
}
}
}
// Внешний контекст
const model = TestModel.model()
model.testAction.exec() // Действие доступно напрямуюsetActionState
setActionState(action: ActionLike<this>): voidОбновляет отслеживание состояния действия в модели. Это публичный метод в контексте ProtoModel, но защищённый в контексте Model.
Параметры:
actionActionLike<this>- Экземпляр действия, для которого нужно обновить состояние
Выбрасывает:
Error если действие не найдено
validateArgs
protected validateArgs(action: ActionLike<this>, ...args: unknown[]): Error[]Валидирует аргументы действия перед его выполнением. Может быть переопределён в дочерних классах для добавления пользовательской валидации.
Передается в конструктор действия. Разработчик вызывает валидацию через действие. Этим проверяется валидность аргументов действия в контексте общего состояния модели.
Подробнее в разделе Валидация аргументов
Параметры:
actionActionLike<this>- Экземпляр ддействия, для которого выполняется валидация...argsunknown[]- Аргументы, переданные действию
Возвращает:
Error[] Массив ошибок валидации. Пустой массив означает, что валидация прошла успешно.
По умолчанию:
Возвращает массив с одной ошибкой, указывающей, что метод не реализован.
Пример:
class CounterModel extends ProtoModel {
@action async increment(value: number): Promise<void> {
// ...
}
protected validateArgs(action: ActionLike<this>, ...args: unknown[]): Error[] {
const errors: Error[] = []
if (action === this.action(this.increment)) {
const value = args[0] as number
if (typeof value !== 'number') {
errors.push(new Error('Value must be a number'))
} else if (value < 0) {
errors.push(new Error('Value must be positive'))
} else if (value > 100) {
errors.push(new Error('Value must not exceed 100'))
}
}
return errors
}
}Публичные методы
isModelOf
isModelOf<T extends ProtoModel>(typeModel: ModelConstructor<T>): booleanПроверяет, является ли текущая модель экземпляром указанного типа модели.
Параметры:
typeModelModelConstructor<T>- Конструктор класса модели для проверки
Возвращает:
boolean true, если модель является экземпляром указанного типа, иначе false
Пример:
class UserModel extends ProtoModel {
// ...
}
class ProductModel extends ProtoModel {
// ...
}
const user = UserModel.model()
console.log(user.isModelOf(UserModel)) // true
console.log(user.isModelOf(ProductModel)) // false
console.log(user instanceof UserModel) // true (альтернативный способ)destructor
destructor(): voidОчищает модель, останавливая все наблюдатели и область эффектов. Должен вызываться, когда модель больше не нужна, чтобы предотвратить утечки памяти.
