如何使用 svelte/store 处理动态数组
How to handle dynamic array with svelte/store
我想从不同的 API 接收多个数据并将它们放在一个大数组中。这个数组应该可以被不同的组件访问。如果调用了所有 API 并收集了数据,组件应列出数组。
我改编了 REPL and added a iteration, to call each API. The array will be filled, but the component is not showing the list. First, I thought its related to reactivity / updating arrays 的代码,但它也不起作用。
import { writable } from 'svelte/store'
export const API_LIST = [
"http://example1.com/api/",
"http://example2.com/api/"
];
export function readAll() {
const { subscribe, update, set } = writable([])
return {
subscribe,
init: async () => {
let alldata = [];
API_LIST.forEach(async function(apiurl) {
const res = await fetch(apiurl)
if (!res.ok) throw new Error('Bad response')
alldata.push( await res.json() );
alldata = alldata;
});
set(alldata);
return alldata;
}
}
}
export const api_store = readAll()
我的组件:
<script>
import { api_store } from 'reader.js';
</script>
<div>
{#await api_store.init()}
<p>wait for reading...</p>
{:then}
<ul>
{#each $api_store as item}
<li>
{item}
</li>
{/each}
</ul>
{:catch error}
<p>Something went wrong: {error.message}</p>
{/await}
</div>
调用完所有API,建立数组后,“等待读取”消失,但显示的列表为空。我可以看到带有 {console.info($api_store)} 的数组内容,因此数据存在。但为什么它没有出现在我的组件列表中?
当您使用 .foreach()
方法并为其提供异步回调时,
代码执行了对
的调用
set(alldata);
和
return alldata;
在 alldata
数组已满之前。
(那是因为 NodeJS 内部是如何工作的——直到调用栈为空时才会调用回调函数)
您可以通过在 alldata
数组中放入 hard-coded 个随机值来测试它。您会看到随机值将出现在浏览器中。
如果您将 .forach()
调用替换为常规 for
循环
在对 fetch()
的所有调用完成之前,您将阻止代码 return。
尝试将您的代码替换为以下内容:
reader.js:
import { writable } from "svelte/store";
export const API_LIST = [
"http://example1.com/api/",
"http://example2.com/api/",
];
export function readAll() {
const { subscribe, update, set } = writable([]);
return {
subscribe,
init: async () => {
let alldata = [];
// API_LIST.forEach(async function (apiurl) {
// const res = await fetch(apiurl);
// if (!res.ok) throw new Error("Bad response");
// alldata.push(await res.json());
// alldata = alldata;
// });
for (let i = 0; i < API_LIST.length; i++) {
const res = await fetch(API_LIST[i]);
if (!res.ok) throw new Error("Bad response");
alldata.push(await res.json());
}
set(alldata);
return alldata;
},
};
}
export const api_store = readAll();
Component.svelte:
<script>
import { api_store } from "./reader.js";
</script>
<div>
{#await api_store.init()}
<p>wait for reading...</p>
{:then}
<ul>
{#each $api_store as item}
<li>
{item}
</li>
{/each}
</ul>
{:catch error}
<p>Something went wrong: {error.message}</p>
{/await}
</div>
这应该有效:)
不需要从 init()
返回 alldata
,它没有用到
替代 for loop
等待所有数据也可以用 Promise.all()
处理
-> REPL
init: async () => {
const requests = API_LIST.map(async url => {
const response = await fetch(url)
if(response.ok) return await response.json()
else throw new Error('bad response')
})
const fetchResults = await Promise.all(requests)
set(fetchResults)
}
我想从不同的 API 接收多个数据并将它们放在一个大数组中。这个数组应该可以被不同的组件访问。如果调用了所有 API 并收集了数据,组件应列出数组。
我改编了 REPL and added a iteration, to call each API. The array will be filled, but the component is not showing the list. First, I thought its related to reactivity / updating arrays 的代码,但它也不起作用。
import { writable } from 'svelte/store'
export const API_LIST = [
"http://example1.com/api/",
"http://example2.com/api/"
];
export function readAll() {
const { subscribe, update, set } = writable([])
return {
subscribe,
init: async () => {
let alldata = [];
API_LIST.forEach(async function(apiurl) {
const res = await fetch(apiurl)
if (!res.ok) throw new Error('Bad response')
alldata.push( await res.json() );
alldata = alldata;
});
set(alldata);
return alldata;
}
}
}
export const api_store = readAll()
我的组件:
<script>
import { api_store } from 'reader.js';
</script>
<div>
{#await api_store.init()}
<p>wait for reading...</p>
{:then}
<ul>
{#each $api_store as item}
<li>
{item}
</li>
{/each}
</ul>
{:catch error}
<p>Something went wrong: {error.message}</p>
{/await}
</div>
调用完所有API,建立数组后,“等待读取”消失,但显示的列表为空。我可以看到带有 {console.info($api_store)} 的数组内容,因此数据存在。但为什么它没有出现在我的组件列表中?
当您使用 .foreach()
方法并为其提供异步回调时,
代码执行了对
set(alldata);
和
return alldata;
在 alldata
数组已满之前。
(那是因为 NodeJS 内部是如何工作的——直到调用栈为空时才会调用回调函数)
您可以通过在 alldata
数组中放入 hard-coded 个随机值来测试它。您会看到随机值将出现在浏览器中。
如果您将 .forach()
调用替换为常规 for
循环
在对 fetch()
的所有调用完成之前,您将阻止代码 return。
尝试将您的代码替换为以下内容:
reader.js:
import { writable } from "svelte/store";
export const API_LIST = [
"http://example1.com/api/",
"http://example2.com/api/",
];
export function readAll() {
const { subscribe, update, set } = writable([]);
return {
subscribe,
init: async () => {
let alldata = [];
// API_LIST.forEach(async function (apiurl) {
// const res = await fetch(apiurl);
// if (!res.ok) throw new Error("Bad response");
// alldata.push(await res.json());
// alldata = alldata;
// });
for (let i = 0; i < API_LIST.length; i++) {
const res = await fetch(API_LIST[i]);
if (!res.ok) throw new Error("Bad response");
alldata.push(await res.json());
}
set(alldata);
return alldata;
},
};
}
export const api_store = readAll();
Component.svelte:
<script>
import { api_store } from "./reader.js";
</script>
<div>
{#await api_store.init()}
<p>wait for reading...</p>
{:then}
<ul>
{#each $api_store as item}
<li>
{item}
</li>
{/each}
</ul>
{:catch error}
<p>Something went wrong: {error.message}</p>
{/await}
</div>
这应该有效:)
不需要从 init()
返回 alldata
,它没有用到
替代 for loop
等待所有数据也可以用 Promise.all()
处理
-> REPL
init: async () => {
const requests = API_LIST.map(async url => {
const response = await fetch(url)
if(response.ok) return await response.json()
else throw new Error('bad response')
})
const fetchResults = await Promise.all(requests)
set(fetchResults)
}