This guide gets a small Askr app running with state and routing.
If you want a generated starter instead of building the example by hand, use the CLI docs and scaffold a project with askr-cli create.
import { state } from '@askrjs/askr';
export function Counter() {
const [count, setCount] = state(0);
return (
<button onClick={() => setCount((prev) => prev + 1)}>
Count: {count()}
</button>
);
}Use islands for a single mounted component (no router).
import { createIsland } from '@askrjs/askr/boot';
import { Counter } from './Counter';
createIsland({
root: document.body,
component: Counter,
});Use router subpath APIs when you need navigation.
import { createSPA } from '@askrjs/askr/boot';
import { route, getRoutes, Link } from '@askrjs/askr/router';
function Home() {
return (
<div>
<h1>Home</h1>
<Link href="/about">About</Link>
</div>
);
}
function About() {
return <h1>About</h1>;
}
route('/', () => <Home />);
route('/about', () => <About />);
await createSPA({
root: document.getElementById('app')!,
routes: getRoutes(),
});createSPA() already mounts the current browser URL when it matches one of the provided routes. Use navigate(path) later for user-driven transitions.
Keep route handlers synchronous. Fetch data in components using resources.
import { resource } from '@askrjs/askr/resources';
function User({ id }: { id: string }) {
const user = resource(
async ({ signal }) => {
const res = await fetch(`/api/users/${id}`, { signal });
return res.json();
},
[id]
);
if (user.pending || !user.value) return <div>Loading...</div>;
if (user.error) return <div>Failed to load user</div>;
return <div>{user.value.name}</div>;
}