SvelteKit提交客户端表单后如何触发load函数更新列表?
问题描述
我有一个表单,提交时不会触发SvelteKit服务器的action,而是通过Svelte组件中的handleSubmit函数处理,代码示例如下:
<script> export let data; let parentObject = writable({ name: '', childObjects: [] }); function addChildObject() { parentObject.update(s => { s.childObjects.push({ name: '', something: '' }); return s; }); } async function handleSubmit(event) { event.preventDefault(); parentObject.subscribe(data => { // 提交逻辑 }); </script> <form class="parent-object-form" method="POST" on:submit={handleSubmit}> <!-- 表单字段 --> <button type="button" on:click={addChildObject}> Add Child Object </button> <button type="submit">Submit</button> </form>
由于需要动态添加、移除对象字段,我特意不使用server action。每次提交表单后,我希望重新调用+page.server.js中的load函数,因为页面上有从服务器获取的parentObjects列表需要渲染:
<table> <tbody> {#each data.parentObject as parent} <!-- 列表项渲染 --> {/each} </tbody> </table>
我需要该列表在表单提交后更新,请问该如何实现?同时有几个疑问:
- 是否可以在提交后手动触发load函数?
- 是否需要在
handleSubmit函数中手动将新对象添加到列表中? - 是否可以手动将动态数据传递给server action?
解决方案与疑问解答
1. 如何在提交后更新列表(触发数据重新加载)
SvelteKit无法直接"调用"load函数,但可以通过两种方式触发页面重新获取数据:
- 使用
invalidate:在handleSubmit完成数据提交后,调用invalidate方法标记数据失效,SvelteKit会自动重新执行+page.server.js的load函数,更新页面的data对象,列表随之刷新。
示例代码:import { invalidate } from '$app/navigation'; async function handleSubmit(event) { event.preventDefault(); // 从store提取数据并提交到后端 let formData; parentObject.subscribe(data => formData = data)(); await fetch('/api/parent-objects', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formData) }); // 标记所有数据失效,触发重新加载 invalidate('*'); // 也可以指定特定数据键,比如invalidate('parentObjects') } - 使用
goto跳转当前页面:如果提交后不需要保留表单状态,可调用goto(window.location.pathname),页面会重新加载并执行load函数,但这种方式会刷新整个页面,体验不如invalidate。
2. 是否需要手动添加新对象到列表?
不需要。只要通过invalidate或goto触发load函数重新执行,后端返回的最新列表会自动替换data.parentObject,页面的#each循环会自动渲染更新后的内容。如果想做乐观更新(提交后立刻显示新数据,无需等待后端响应),可以先手动把新对象加到列表里,等后端返回后再用真实数据替换,提升用户体验。
3. 是否可以手动将动态数据传递给server action?
可以。即使是动态字段,依然可以把store中的数据整理成合适格式,通过fetch调用server action的端点:
- 用JSON传递:
import { page } from '$app/stores'; async function handleSubmit(event) { event.preventDefault(); let formData; parentObject.subscribe(d => formData = d)(); // 调用server action const response = await fetch(`${$page.url.origin}/parent-objects`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(formData) }); if (response.ok) { invalidate('*'); } } - 用
FormData传递:将动态子对象转换成数组字段格式:async function handleSubmit(event) { event.preventDefault(); let data; parentObject.subscribe(d => data = d)(); const formData = new FormData(); formData.append('name', data.name); // 遍历子对象,添加到FormData data.childObjects.forEach((child, index) => { formData.append(`childObjects[${index}][name]`, child.name); formData.append(`childObjects[${index}][something]`, child.something); }); await fetch('/parent-objects', { method: 'POST', body: formData }); invalidate('*'); }
这样server action就能接收到你传递的动态数据。
内容的提问来源于stack exchange,提问作者fedest
相关产品推荐
相关产品推荐

