frontend-hamroun
Version:
A lightweight frontend JavaScript framework with React-like syntax
85 lines (84 loc) • 2.82 kB
JavaScript
import { createElement } from './jsx-runtime.js';
export class Component {
constructor(props = {}) {
this.state = {};
this.element = null;
this._mounted = false;
this.props = props;
}
componentDidMount() {
// Hook for after component is mounted
}
async setState(newState) {
const prevState = { ...this.state };
this.state = { ...prevState, ...newState };
console.log(`${this.constructor.name} state updated:`, {
prev: prevState,
next: this.state
});
await Promise.resolve(); // Ensure state is updated before re-render
if (this._mounted) {
await this.update();
}
else {
await this.update();
}
}
_replayEvents(oldElement, newElement) {
const oldEvents = oldElement.__events || {};
Object.entries(oldEvents).forEach(([event, handler]) => {
newElement.addEventListener(event, handler);
});
newElement.__events = oldEvents;
}
_deepCloneWithEvents(node) {
const clone = node.cloneNode(false);
// Copy events from original element
const events = node.__events || {};
clone.__events = events;
Object.entries(events).forEach(([event, handler]) => {
clone.addEventListener(event, handler);
});
// Clone children
Array.from(node.childNodes).forEach(child => {
if (child instanceof HTMLElement) {
clone.appendChild(this._deepCloneWithEvents(child));
}
else {
clone.appendChild(child.cloneNode(true));
}
});
return clone;
}
async update() {
const vdom = this.render();
if (!vdom)
return document.createTextNode('');
const rendered = await createElement(vdom);
if (rendered instanceof HTMLElement) {
return this._updateElement(rendered);
}
const wrapper = document.createElement('div');
wrapper.appendChild(rendered);
return this._updateElement(wrapper);
}
async _updateElement(rendered) {
const newElement = this._deepCloneWithEvents(rendered);
newElement.__instance = this;
if (!this.element) {
this.element = newElement;
if (!this._mounted) {
this._mounted = true;
queueMicrotask(() => this.componentDidMount());
}
}
else if (this.element.parentNode) {
this.element.parentNode.replaceChild(newElement, this.element);
this.element = newElement;
}
return this.element;
}
render() {
throw new Error('Component must implement render() method');
}
}