Hooks
PawaJS provides a set of powerful hooks to manage component state, lifecycle, and side effects.
$state
The core of PawaJS reactivity. $state creates a reactive object that automatically triggers UI updates when its .value property changes. It can be used inside or outside components.
import { $state } from 'pawajs';
// Global state, accessible anywhere
const appName = $state('My Pawa App');
console.log(appName.value); // "My Pawa App"
appName.value = 'New App Name'; // Will trigger updates in any component using appName
import { $state, useInsert, html } from 'pawajs';
const MyComponent = () => {
const count = $state(0); // Reactive number
const user = $state({ name: 'Alice', age: 30 }); // Reactive object
const items = $state(['apple', 'banana']); // Reactive array
useInsert({ count, user, items });
return html`
<p>Count: @{count.value}</p>
<p>User: @{user.value.name}, @{user.value.age}</p>
<ul>
<li for-each="item in items.value">@{item}</li>
</ul>
`;
};
$state can also be initialized with a function that returns a value or a Promise for asynchronous state.
useInsert
Makes variables, state, and functions available within a component's template. It's how you "inject" your component's logic into its HTML.
import { $state, useInsert, html } from 'pawajs';
const MyComponent = () => {
const name = $state('World');
const greet = () => `Hello, ${name.value}!`;
useInsert({ name, greet }); // Expose 'name' state and 'greet' function
return html`
<h1>@{greet()}</h1>
<input type="text" @value="@{name.value}" on-input="name.value = e.target.value">
`;
};
runEffect
Executes side effects. It can run on component mount, before mount, on reactive dependency changes, or as a read-only reactive effect. It can also return a cleanup function.
import { runEffect, $state } from 'pawajs';
const globalCounter = $state(0);
// Global effect: logs when globalCounter changes
runEffect(() => {
console.log('Global counter changed:', globalCounter.value);
}, [globalCounter]);
import { $state, runEffect, useInsert, html } from 'pawajs';
const MyEffectComponent = () => {
const count = $state(0);
// Runs once on mount, returns cleanup
runEffect(() => {
console.log('Component mounted!');
return () => console.log('Component unmounted!');
}, null);
// Runs before mount (number of milliseconds)
runEffect(() => {
console.log('Running before mount (100ms delay)');
}, 100);
// Runs when 'count' changes
runEffect(() => {
console.log('Count changed:', count.value);
}, [count]);
useInsert({ count });
return html`
<button on-click="count.value++">Increment: @{count.value}</button>
`;
};
useContext & setContext
The Context API allows you to pass data deep down the component tree without manually passing props at every level. setContext creates a context handle, and useContext consumes the value from a parent provider.
import { setContext, useContext, useInsert, html, $state } from 'pawajs';
// 1. Create a context handle
const ThemeContext = setContext();
// 2. Provider component
const ThemeProvider = ({ children }) => {
const theme = $state('light');
ThemeContext.setValue({ theme }); // Set the context value
useInsert({ children });
return html`<div>${children}</div>`;
};
// 3. Consumer component
const ThemeButton = () => {
const { theme } = useContext(ThemeContext); // Consume the context
useInsert({ theme });
return html`
<button on-click="theme.value = theme.value === 'light' ? 'dark' : 'light'">
Toggle Theme: @{theme.value}
</button>
`;
};
// Usage:
// <theme-provider><theme-button></theme-button></theme-provider>
useRef
Creates a mutable ref object that can hold a reference to a DOM element or component instance. Use it with the ref directive.
import { useRef, useInsert, html, runEffect } from 'pawajs';
const FocusInput = () => {
const inputRef = useRef(); // Create a ref object
runEffect(() => {
// Access the DOM element after it's mounted
if (inputRef.value) {
inputRef.value.focus();
}
}, null); // Run on mount
useInsert({ inputRef });
return html`
<input ref="inputRef" type="text" placeholder="I will be focused!">
`;
};
useValidateComponent
Provides runtime prop validation for your components, helping ensure type safety and required props.
import { useValidateComponent, html } from 'pawajs';
const MyValidatedComponent = ({ title, count }) => {
// ... component logic
return html`<div>@{title()} - @{count()}</div>`;
};
useValidateComponent(MyValidatedComponent, {
title: { type: String, strict: true, err: 'Title is required!' },
count: { type: Number, default: 0 }
});
useServer
A hook for isomorphic components, providing utilities to serialize data on the server and retrieve it during client-side hydration (Continuity Rendering Model).
import { useServer, useInsert, html, isResume } from 'pawajs';
const ServerDataComponent = () => {
const { setServerData, getServerData } = useServer();
let initialData = { value: 'Loading...' };
if (isResume()) { // Only available during client-side hydration
initialData = getServerData();
} else {
// This part runs on the server during SSR
// setServerData({ value: 'Data from Server!' });
}
const data = $state(initialData.value);
useInsert({ data });
return html`<p>Data: @{data.value}</p>`;
};
useAsync
Enables asynchronous component rendering. Use $async to wrap PawaJS hooks that depend on awaited values, ensuring they run in the correct context.
import { useAsync, $state, useInsert, html } from 'pawajs';
const AsyncUserComponent = async () => {
const { $async, onSuspense } = useAsync();
onSuspense(html`<div>Loading user data...</div>`); // Optional loading state
const response = await fetch('/api/user/1');
const userData = await response.json();
const user = $async(() => $state(userData)); // Reactive state from async data
$async(() => useInsert({ user }));
return html`
<div>
<h2>@{user.value.name}</h2>
<p>Email: @{user.value.email}</p>
</div>
`;
};
isResume
A boolean hook that returns true if the current component is being hydrated on the client after server-side rendering, and false otherwise. Useful for client-only logic during hydration.
import { isResume, useInsert, html } from 'pawajs';
const HydrationCheck = () => {
const isHydrating = isResume();
useInsert({ isHydrating });
return html`
<p>Client-side hydration: @{isHydrating ? 'Yes' : 'No'}</p>
`;
};
forwardProps
Used within a component to explicitly forward any unconsumed props (including rest props --) to a nested element or another component. This is crucial for building wrapper components that need to pass down attributes.
import { forwardProps, useInsert, html } from 'pawajs';
const MyWrapperButton = (props) => {
forwardProps(props); // Forward all incoming props
useInsert({ props });
return html`
<div class="wrapper">
<button -->Click Me</button> <!-- Rest props will apply here -->
</div>
`;
};
// Usage: <my-wrapper-button class="my-class" data-id="123"></my-wrapper-button>
useInnerContext
Allows a component to access the context of its immediate parent element or component. This is useful for tightly coupled components where a child needs to interact with its direct parent's state or methods.
import { useInnerContext, useInsert, html, $state } from 'pawajs';
const ParentComponent = () => {
const parentState = $state('I am the parent');
useInsert({ parentState });
return html`
<div state-parent-data="parentState.value"> <!-- Inline state creates context -->
<child-component></child-component>
</div>
`;
};
const ChildComponent = () => {
const parentContext = useInnerContext(); // Access parent's context
useInsert({ parentContext });
return html`
<p>Message from parent: @{parentContext.parentData.value}</p>
`;
};
Page Not Found
We couldn't find the page you're looking for. It might have been moved or deleted.
Go back home