rynex
Version:
A minimalist TypeScript framework for building reactive web applications with no virtual DOM
133 lines • 3.92 kB
JavaScript
/**
* Rynex Lifecycle Hooks
* Component lifecycle management
*/
import { effect } from '../state.js';
/**
* Component mount lifecycle hook
* Executes callback when element is mounted to DOM
*/
export function onMount(element, callback) {
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach((node) => {
if (node === element || node.contains?.(element)) {
const cleanup = callback();
if (cleanup && typeof cleanup === 'function') {
element.dataset.cleanup = 'registered';
element.__cleanup = cleanup;
}
observer.disconnect();
}
});
}
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
// Check if already mounted
if (document.body.contains(element)) {
const cleanup = callback();
if (cleanup && typeof cleanup === 'function') {
element.dataset.cleanup = 'registered';
element.__cleanup = cleanup;
}
observer.disconnect();
}
}
/**
* Component unmount lifecycle hook
* Executes callback when element is removed from DOM
*/
export function onUnmount(element, callback) {
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
mutation.removedNodes.forEach((node) => {
if (node === element || node.contains?.(element)) {
callback();
observer.disconnect();
}
});
}
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
/**
* Component update lifecycle hook
* Executes callback when element attributes or children change
*/
export function onUpdate(element, callback) {
const observer = new MutationObserver((mutations) => {
callback(mutations);
});
observer.observe(element, {
attributes: true,
childList: true,
subtree: true,
characterData: true
});
return () => observer.disconnect();
}
/**
* Watch a reactive value and execute callback when it changes
* Returns cleanup function
*/
export function watch(getter, callback, options) {
let oldValue = getter();
if (options?.immediate) {
callback(oldValue, oldValue);
}
const cleanup = effect(() => {
const newValue = getter();
if (newValue !== oldValue) {
callback(newValue, oldValue);
oldValue = newValue;
}
});
return cleanup;
}
/**
* Watch effect - runs effect immediately and re-runs when dependencies change
* Similar to effect but with explicit cleanup handling
*/
export function watchEffect(effectFn) {
let cleanup;
const wrappedEffect = () => {
if (cleanup) {
cleanup();
}
cleanup = effectFn();
};
const stopEffect = effect(wrappedEffect);
return () => {
if (cleanup) {
cleanup();
}
stopEffect();
};
}
/**
* On error handler for component errors
* Catches and handles errors within a component tree
*/
export function onError(element, handler) {
const errorHandler = (event) => {
if (element.contains(event.target)) {
event.preventDefault();
handler(event.error || new Error(event.message));
}
};
window.addEventListener('error', errorHandler);
onUnmount(element, () => {
window.removeEventListener('error', errorHandler);
});
}
//# sourceMappingURL=lifecycle.js.map