Skip to content

Instantly share code, notes, and snippets.

@sor4chi
Created January 29, 2025 06:18
Show Gist options
  • Save sor4chi/b7b6135f1c86459374420763a9479763 to your computer and use it in GitHub Desktop.
Save sor4chi/b7b6135f1c86459374420763a9479763 to your computer and use it in GitHub Desktop.
Hono SPA Router
import {
MouseEventHandler,
ReactNode,
StrictMode,
useCallback,
useSyncExternalStore,
} from "react";
import { createRoot } from "react-dom/client";
import { Hono } from "hono";
import { Action, createBrowserHistory, Update } from "history";
let page: ReactNode = undefined;
const history = createBrowserHistory();
const ROUTER_UPDATE_EVENT = "hono-spa-router:update";
const app = new Hono();
app.get("/", (c) => c.text("Hello, Hono SPA Router!"));
app.get("/a", (c) => c.text("Hello, A!"));
app.get("/b", (c) => c.text("Hello, B!"));
async function onLocationChange({ location }: Update): Promise<void> {
const res = await app.request(location.pathname);
page = await res.text();
window.dispatchEvent(new CustomEvent(ROUTER_UPDATE_EVENT));
}
history.listen(onLocationChange);
await onLocationChange({
action: Action.Replace,
location: history.location,
});
function Link(props: { to: string; children: any; onClick?: Function }) {
const { to, children, onClick, ...others } = props;
const handleClick = useCallback(
({ onClick, to }: { onClick?: Function; to: string }): MouseEventHandler =>
(e) => {
onClick?.(e);
e.preventDefault();
history.push(to);
},
[onClick, to]
);
return (
<a href={to} {...others} onClick={handleClick({ onClick, to })}>
{children}
</a>
);
}
function getSnapshot() {
return page;
}
function subscribe(callback: () => void) {
window.addEventListener(ROUTER_UPDATE_EVENT, callback);
return () => window.removeEventListener(ROUTER_UPDATE_EVENT, callback);
}
function App() {
const page = useSyncExternalStore(subscribe, getSnapshot);
return <main>{page}</main>;
}
createRoot(document.getElementById("root")!).render(
<StrictMode>
<h1>Hono SPA Router</h1>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/a">A</Link>
</li>
<li>
<Link to="/b">B</Link>
</li>
</ul>
</nav>
<App />
</StrictMode>
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment