Svelte中如何创建由异步请求填充的派生Store?
实现基于异步请求的派生Store
首先,我们需要创建一个派生Store(child),它依赖parent store的值发起异步API请求,并在视图中处理加载、成功、失败三种状态。
1. 创建child派生Store
在child.js中,使用Svelte的derived函数实现:
// child.js import { derived } from 'svelte/store'; import parent from './parent.js'; // 封装异步API请求 async function fetchRelatedData(parentValue, signal) { // 如果parent没有值,直接返回null if (!parentValue) return null; try { const response = await fetch( `https://api.example.com/get-data?key=${parentValue}`, { signal } // 用于取消请求的信号 ); if (!response.ok) throw new Error(`请求失败:${response.status}`); return await response.json(); } catch (err) { // 忽略请求取消的错误 if (err.name !== 'AbortError') throw err; } } // 创建派生store export const child = derived( parent, async ($parent, set) => { // 初始化状态:加载中 set({ loading: true, data: null, error: null }); // 创建AbortController,用于取消未完成的请求 const controller = new AbortController(); try { const data = await fetchRelatedData($parent, controller.signal); // 请求成功,更新状态 set({ loading: false, data, error: null }); } catch (err) { // 请求失败,更新错误状态 set({ loading: false, data: null, error: err.message }); } // 清理函数:当parent值变化或组件销毁时,取消当前请求 return () => controller.abort(); }, // 初始默认状态 { loading: true, data: null, error: null } );
2. 在视图中使用child Store
在Svelte组件里,通过$child直接访问store的当前值,根据状态渲染不同内容:
<script> import { child } from './child.js'; import parent from './parent.js'; </script> <!-- 输入框测试parent值变化 --> <input type="text" bind:value={$parent} placeholder="输入parent值触发请求" > <!-- 根据child状态渲染内容 --> {#if $child.loading} <div>加载中,请稍候...</div> {:else if $child.error} <div class="error">出错了:{$child.error}</div> {:else if $child.data} <div class="content"> <h3>获取到的关联数据:</h3> <pre>{JSON.stringify($child.data, null, 2)}</pre> </div> {:else} <div>请输入内容触发数据请求</div> {/if}
关键说明
- 异步派生核心:
derived的第二个参数支持异步函数,通过set手动更新store值,这是处理异步逻辑的关键。 - 状态统一管理:用包含
loading/data/error的对象管理状态,让视图清晰区分等待、成功、失败三种场景。 - 避免竞态问题:通过
AbortController在parent值变化时取消未完成的请求,防止旧请求结果覆盖新数据。
内容的提问来源于stack exchange,提问作者Jonathan Herrera
相关产品推荐
相关产品推荐

