SkateJS — это библиотека для создания веб-компонентов на базе стандартов Custom Elements и Shadow DOM. Она обеспечивает структурированный и реактивный подход к построению интерфейсов, позволяя создавать изолированные, повторно используемые компоненты с минимальной связностью.
Компоненты в SkateJS создаются с помощью функции
defineComponent или наследованием от базового класса
Component. Основная структура компонента включает:
props) — реактивные данные,
которые управляют поведением и отображением компонента.state) — внутренние данные
компонента, также реактивные, но недоступные извне напрямую.render) — метод, возвращающий
виртуальное DOM-представление компонента.Пример базового компонента:
import { h, defineComponent, Component } from 'skatejs';
class MyComponent extends Component {
static get props() {
return {
name: String
};
}
render() {
return <div>Hello, {this.name}</div>;
}
}
customElements.define('my-component', MyComponent);
Иммутабельность данных — это концепция, при которой данные не изменяются напрямую, а вместо этого создаются новые объекты при любом обновлении. В контексте SkateJS это критически важно для реактивного обновления компонентов, предотвращения непредсказуемого поведения и упрощения отладки.
Невозможность прямого изменения объекта Любые изменения состояния или пропсов должны происходить через методы, создающие новые объекты.
// Неправильно:
this.state.items.push(newItem);
// Правильно:
this.state = {
...this.state,
items: [...this.state.items, newItem]
};Использование неизменяемых структур данных
JavaScript предоставляет средства для создания копий объектов и
массивов: Object.assign, spread-операторы
(...), методы массивов .map(),
.filter(), .reduce().
Прозрачная реактивность SkateJS отслеживает изменения пропсов и состояния с использованием геттеров и сеттеров, поэтому прямое мутирование данных может не вызвать перерисовку компонента.
Пропсы компонентов SkateJS рекомендуется рассматривать как входные данные, которые не должны изменяться внутри компонента. Изменение пропсов должно происходить из внешнего контекста, что обеспечивает предсказуемость.
class TodoList extends Component {
static get props() {
return {
items: Array
};
}
render() {
return (
<ul>
{this.items.map(item => <li>{item}</li>)}
</ul>
);
}
}
// Обновление пропсов через новый массив
todoList.items = [...todoList.items, 'New Task'];
Состояние компонента предназначено для хранения локальных реактивных данных. При изменении состояния создается новый объект, чтобы SkateJS корректно инициировал обновление компонента.
class Counter extends Component {
static get props() {
return {};
}
constructor() {
super();
this.state = { count: 0 };
}
increment() {
this.state = { count: this.state.count + 1 };
}
render() {
return <div>Count: {this.state.count}</div>;
}
}
SkateJS позволяет использовать реактивные объекты и массивы, но для соблюдения иммутабельности рекомендуется комбинировать их с подходами функционального программирования:
.map() и .filter() для трансформации
массивовObject.assign() или spread-оператор для объектовthis.state = {
...this.state,
todos: this.state.todos.map(todo =>
todo.id === updatedTodo.id ? { ...todo, done: true } : todo
)
};
Для вложенных объектов и массивов иммутабельность сохраняется через глубокое копирование или использование специализированных библиотек:
// Изменение вложенного объекта
this.state = {
...this.state,
user: {
...this.state.user,
address: {
...this.state.user.address,
city: 'Москва'
}
}
};
Библиотеки вроде Immer или Immutable.js упрощают работу с глубокими структурами, позволяя писать код, который выглядит мутабельным, но фактически создает новые объекты.
SkateJS активно использует кастомные события
(CustomEvent) для взаимодействия между компонентами. При
передаче данных через события важно не мутировать исходные
объекты, а передавать копии:
this.dispatchEvent(
new CustomEvent('update', {
detail: { items: [...this.state.items, newItem] }
})
);
Иммутабельность данных в SkateJS обеспечивает:
Правильное применение иммутабельности в SkateJS формирует структурированную и предсказуемую архитектуру приложения, что критично для больших и сложных интерфейсов.