## Demo: reload-form-data
### ReloadFormData.svelte
```svelte
Each successful submit appends the name to an in-memory list on the server. The hydrated version refetches /api/guestbook after a successful submit and updates the
list in place. The plain version submits natively, the page re-renders with a fresh guestbook serverProp, and the new name shows up after the reload.
With {'{@attach enhance(...)}'}
Plain HTML
```
### Guestbook.svelte
```svelte
{#if entries.length === 0}
No entries yet. Be the first to sign.
{:else}
{#each entries as entry (entry.id)}
-
{entry.name}
{formatTime(entry.at)}
{/each}
{/if}
```
### routes.ts
```ts
import { Mochi, fail, success } from 'mochi-framework';
import type { MochiRouteValue } from 'mochi-framework';
type GuestbookEntry = { id: string; name: string; at: number };
const guestbook: GuestbookEntry[] = [];
export const routes: Record = {
'/api/guestbook': Mochi.api(({ method }) => {
if (method !== 'GET') {
return new Response('Method not allowed', { status: 405 });
}
return Response.json({ entries: [...guestbook].reverse() });
}),
'/demos/reload-form-data': Mochi.page('./src/demos/reload-form-data/ReloadFormData.svelte', {
serverProps: () => ({ guestbook: [...guestbook].reverse() }),
actions: {
guestbookSign: ({ formData }) => {
const name = String(formData.get('name') ?? '').trim();
if (!name) {
return fail(400, { error: 'Name required' });
}
if (name.length > 50) {
return fail(400, { error: 'Name too long (max 50 chars)' });
}
guestbook.push({ id: crypto.randomUUID(), name, at: Date.now() });
return success({});
},
},
}),
};
```
### index.ts
```ts
import { Mochi, logger } from 'mochi-framework';
await Mochi.serve({
port: 3333,
development: process.env.MODE === 'development',
routes: {
'/': Mochi.page('./src/Home.svelte'),
},
});
logger.info('Server running at http://localhost:3333');
```