State Manager
Nuxoblivius включает встроенный State Manager, обеспечивающий удобное управление состоянием приложения.
Основой являются классы, что позволяет строить гибкую и расширяемую архитектуру, а также легко интегрировать собственные механизмы работы с данными.
Создание Store объекта
Nuxoblivius поддерживает два подхода к созданию Store:
Singleton— единый экземпляр состояния, доступный во всём приложении.Factory— генерация новых экземпляров Store при каждом вызове.
Как работает создание Store:
— Все свойства класса, кроме начинающихся с _, автоматически становятся реактивными.
— Store реализован на базе классов, поэтому вы можете использовать все привычные возможности ООП: наследование, инкапсуляцию, полиморфизм.
Factory (через subStore/defineFactory):
Более безопасный вариант, при котором Store создаётся в контексте конкретного компонента.
— Такой Store изолирован и уничтожается вместе с компонентом;
— Поддерживает хуки жизненного цикла (onMounted,onUnmounted) во Vue 3;
— Удобен для локального состояния, которое не должно «утекать» за пределы компонента;
import { subStore } from "nuxoblivius";
class Counter {
private value: number = 0;
public getValue(): number {
return this.value;
}
public increase(): void {
this.value += 1;
}
}
export default () => subStore(Counter);import { defineFactory } from "nuxoblivius";
class Counter {
private value: number = 0;
public getValue(): number {
return this.value;
}
public increase(): void {
this.value += 1;
}
}
export default defineFactory(Counter);<script setup lang="ts">
import useCounter from "@/store/Counter";
const counter = useCounter();
</script>
<template>
<button @click="counter.increase()">Counter: {{ counter.getValue() }}</button>
</template>Singleton (через defineStore / defineSingleton):
Singleton используется тогда, когда нужно иметь единый источник правды во всём приложении. Store, созданный через defineStore/defineSingleton, существует в одном экземпляре и доступен из любой части кода.
Зачем это нужно:
— хранение глобального состояния, которое должно быть одинаковым для всех компонентов;
— управление настройками приложения (тема, язык, конфигурация);
— хранение данных пользователя (сессия, токен, профиль);
— кэширование или другие данные, которые не должны пересоздаваться при каждом обращении;
import { defineStore } from "nuxoblivius";
class Counter {
private value: number = 0;
public getValue(): number {
return this.value;
}
public increase(): void {
this.value += 1;
}
}
export default defineStore(Counter);import { defineSingleton } from "nuxoblivius";
class Counter {
private value: number = 0;
public getValue(): number {
return this.value;
}
public increase(): void {
this.value += 1;
}
}
export default defineSingleton(Counter);<script setup lang="ts">
import Counter from "@/store/Counter";
</script>
<template>
<button @click="Counter.increase()">Counter: {{ Counter.getValue() }}</button>
</template>Инкапсуляция данных
Nuxoblivius поддерживает разные подходы к инкапсуляции состояния:
— Классический ООП-подход — вы можете скрывать данные за приватными свойствами и методами;
— Встроенные механизмы библиотеки — Nuxoblivius позволяет ограничивать доступ к данным через специальные методы и правила реактивности, сохраняя при этом контроль над изменением состояния.
Таким образом, можно сочетать привычные средства инкапсуляции из ООП с возможностями, встроенными в сам фреймворк.
Классический подход (getter/setter):
Классический подход строится через: методы доступа
import { subStore } from "nuxoblivius";
class Language {
private currentLanguage: string;
public getCurrent(): string {
return this.currentLanguage;
}
public setCurrent(lang: string): void {
this.currentLanguage = lang;
}
}
export default () => subStore(Language);import useLanguage from "@/store/Language";
const language = useLanguage();
language.setCurrent("ru");
language.getCurrent(); // ruТеневая переменная (Метод двойного свойства):
⚠ Важно
Доступно только для примитивных объектов (строка, число, булевое, объект)
В Nuxoblivius используется механизм теневых переменных, позволяющий отделять внутреннее состояние от публичного.
— Свойство с префиксом
_считается внутренним — оно доступно только внутри класса и не участвует в реактивности напрямую.
— Свойство без префикса создаётся как «зеркало» внутреннего и используется для внешнего доступа.
Таким образом, данные хранятся безопасно внутри объекта, а снаружи доступны только через контролируемый интерфейс. Это сочетает привычную инкапсуляцию из ООП с реактивной моделью Nuxoblivius.
import { subStore } from "nuxoblivius";
class Info {
private _message: string; // Теневая перемменая, внутренняя
readonly message!: string; // Открытая наружная
public setMessage(newMessage: string): void {
this._message = newMessage;
}
}
export default () => subStore(Info);import useInfo from "@/store/Info";
const info = useInfo();
info.setMessage("Hello world!");
info.message; // Hello world!Кастомный setter (Свойство которое может себя модернизировать)
В Nuxoblivius используется механизм методы доступа теневых переменных, позволяющий отделять внутреннее состояние от публичного а так-же его кастомизировать.
— Свойство с префиксом
_считается внутренним — оно доступно только внутри класса и не участвует в реактивности напрямую.
— Свойство без префикса создаётся как «зеркало» внутреннего и используется для внешнего доступа. Оно является методом доступа
setи позволяет модифицировать входные данные.
import { subStore } from "nuxoblivius";
class OTPValue {
private _value: string;
set value(value: unknown) {
const valueAsString = `${value}`;
if (valueAsString.lenght > 8) {
this._value = valueAsString.slice(1, 8);
return;
}
this._value = valueAsString;
}
}
export default () => subStore(OTPValue);import useOTPValue from "@/store/OTPValue";
const otp = useOTPValue();
otp.value = "1020202";
otp.value; // 020202Низкоуровневый доступ (.ref)
У любого Store в Nuxoblivius есть специальное свойство .ref. Оно предоставляет низкоуровневый доступ к экземпляру класса, из которого был создан Store.
Зачем это может быть нужно:
— Получение информации, о свойсве (Название, Значение);
— Подписать/Отписаться от изменений;
import { subStore } from "nuxoblivius";
class TestStore {
public myVar: string;
}
export default () => subStore(TestStore);import useTestStore from "@/store/TestStore";
const testStore = useTestStore();
testStore.ref.myVar.name; // "myVar"
testStore.ref.myVar.value; // undefined
testStore.myVar = "Hello!";
testStore.ref.myVar.value; // "Hello!"
const unWatchHandle = testStore.ref.myVar.watch(() => {
console.log("Value updated!");
}, "some-key");
testStore.ref.myVar.unwatch("some-key");⚡ Event: Создан
После сборки методами defineStore или subStore вызывается событие mounted. В соответствующей функции можно произвести желаемые действия:
import { defineStore } from "nuxoblivius";
class Test {
mounted() {
console.log("Я собран!");
}
}
export default defineStore(Test);API
defineStore
interface Store<T> {
ref: Record<keyof T, { value: any, watch(handle: Function): void }>
}
declare function defineStore<T extends any>(class: { new(): T }): T & Store<T>subStore
interface Store<T> {
ref: Record<keyof T, { value: any, watch(handle: Function): void }>
}
declare function subStore<T extends any>(class: { new(): T }): T & Store<T>