Hooks
Hooks are functions that let you "hook into" PawaJS features from your components. They are essential for managing state, side effects, and interacting with the DOM.
useInsert
The useInsert hook is fundamental for making variables and functions from your component's scope available to its template. Without it, you cannot use variables in directives or interpolation.
import { html, useInsert } from "pawajs";
export const MyComponent = () => {
const message = "Hello from a variable!";
const handleClick = () => alert('Clicked!');
// Expose to the template
useInsert({ message, handleClick });
return html`
<p>@{message}</p>
<button on-click="handleClick()">Click me</button>
`;
};
runEffect
runEffect is PawaJS's versatile hook for managing side effects and lifecycle events. Its behavior changes based on the second argument (dependencies).
Reactive Effect (Array)
Pass an array of reactive variables. The effect runs when they change. The return function is the cleanup (unmount) handler.
runEffect(() => {
console.log(`The count is now: ${count.value}`);
return () => console.log('Cleanup/Unmount');
}, [count]); // Dependency array
Mount Hook (null)
Pass null to run the effect only once when the component mounts. The return function runs on unmount.
runEffect(() => {
console.log('Mounted');
return () => console.log('Unmounted');
}, null);
Before Mount (Number)
Pass any number to run the effect before the component mounts.
runEffect(() => console.log('Before Mount'), 1);
Scoped/Read-Only Effect (Object)
Pass an object (like a ref or {component: true}) to create a read-only effect tied to that scope. Unlike the others, this is passed directly to the internal createEffect.
const divRef = useRef();
// ...
runEffect(() => {
// Read-only effect tied to element
}, divRef.value);
useRef
useRef provides a way to get a direct reference to a DOM element. This is useful for interacting with elements imperatively, like focusing an input.
import { useRef, useInsert, html } from "pawajs";
const inputRef = useRef();
useInsert({ inputRef });
const focusInput = () => {
inputRef.value.focus();
};
return html`
<input ref="inputRef">
<button on-click="focusInput">Focus Input</button>
`;
useValidateComponent
This hook allows you to define prop types and default values for your components, providing validation and ensuring robustness.
import { useValidateComponent, html } from "pawajs";
const Card = ({ title, content }) => { /* ... */ };
useValidateComponent(Card, {
title: { type: String, required: true },
content: { type: String, default: 'No content provided.' }
});
useContext & setContext
setContext creates a context provider mechanism, and useContext allows you to subscribe to it.
import { useContext, setContext, html, useInsert } from "pawajs";
// Define context globally
const ThemeContext = setContext();
const App = () => {
// Set value for descendants
ThemeContext.setValue({ mode: 'dark' });
return html`<theme-button></theme-button>`;
};
const ThemeButton = () => {
const theme = useContext(ThemeContext);
useInsert({ theme });
return html`<button>Current theme: @{theme.mode}</button>`;
};
useAsync
useAsync helps manage asynchronous operations within a component and provides a way to
show a ui loading while the async component is waiting onSuspence
import { useAsync, html, $state, useInsert } from "pawajs";
const DataComponent = () => {
const { $async, onSuspence } = useAsync();
onSuspence(html`<loading></loading> `)
const res = await fetch('/api/data'),then(res => res.json());
const data = $async(()=>$state(res));
$async(()=>useInsert({ data, loadData }));
// ...
};
useServer
useServer facilitates data transfer from server-side rendering to the client.
It provides setServerData to store data during SSR and
getServerData to retrieve it during hydration.
On server streaming pawajs (pawa-ssr) uses useServer and useAync hook (onSuspense) to mark suspense boundaries where pawa-ssr resovles it later and update the page with the resovle asynchronous component output.
import { useServer, html, useInsert } from "pawajs";
import { isServer } from "pawajs/server";
const ServerDataComponent = () => {
const { setServerData, getServerData } = useServer();
let data = { message: "" };
if (isServer()) {
data = { message: "Hello from Server!" };
setServerData(data);
} else {
data = getServerData() || { message: "Hydrating..." };
}
useInsert({ data });
return html`<div>Server says: @{data.message}</div>`;
};
isResume
isResume is a helper that returns true if the current component is being hydrated (resumed) from server-rendered HTML. This is useful for distinguishing between a hydration pass and a fresh client-side render.
import { isResume, html } from "pawajs";
const Component = () => {
const status = isResume() ? 'Hydrating' : 'Rendering';
useInsert({status});
return html`<div>@{status}</div>`;
};