在Svelte中存储远程数据的位置,以便使用Svelte和D3进行响应数据可视化(最佳实践)



免责声明:我对svelte、D3和通用JavaScript模式都没有很好的经验。但我真的很喜欢它,所以我真的想学习它,并且已经投入了相当长的时间。尽管如此,这感觉像是一个非常基本的问题,让我很恼火。我希望它不会太令人困惑,也许有人会有一个想法。

它基本上是关于如何以高效、可复制和"无"的方式设置一个简单的图(让它成为条形图);最佳实践";方法我想我主要关心的是如何传递数据并将其用于不同的任务。例如,我认为在一个单独的组件中分离出天平的结构(使用d3)可能是个好主意。但是,该组件需要访问数据(在最好的情况下,可能还需要访问图表容器的响应宽度)。

然而,另一个组件中的条形图也需要访问数据,以便了解如何绘制矩形。

我对JavaScript的一个普遍误解(我想这是正确的词)是,我不知道如何异步获取数据(例如使用浏览器fetch或D3的csv方法)。我根本无法获取数据,然后将其作为道具传递给另一个组件。因为我所传递的将是一个承诺。。。

所以我有一个非常基本的REPL,它显示了我脑海中的一些知识:https://svelte.dev/repl/398f4c21b7a9409a9811fd8e38703a36?version=3.44.1

它看起来像这样。在App.html中,我获取要用于多种目的的数据。然而,我不能";把它拿出来";该组件。

<script>
import Chart from "./Chart.svelte"

const url = "https://api.github.com/search/repositories?q=stars:>100000";

async function getData(){
let response = await fetch(url)
let data = await response.json()
console.log(data)
}

//async function getDataLocal(){
//  let data = await d3.csv(<path_to_data>)
//      return await data
//  }


let data = await getData()

</script>
<Chart {data}>Do Something with the data. Make the chart, build the scales, ....</Chart>

所以主要的问题是:

  • 有关于如何学习使用远程数据、svelte和一些D3构建可持续图形的资源吗。我已经看了很多youtube视频,我想我会重新看Matthias Stahl的视频;)

  • 在这种情况下使用存储来存储数据是个好主意吗

  • 更具体一点:由于数据(可能)是固定的,但维度不是:什么是让应用程序知道重新计算天平等的好方法/地方?

这里有三个单独的问题:

  • 获取、存储和检索数据(也称为数据源层)
  • 操作/转换数据(也称为业务逻辑层)
  • 显示数据(也称为表示层)

我将把最后一部分放在一边,因为它只涉及D3(如果这是你选择的可视化库的话),而且网上有很多关于这个主题的资源,我将专注于你问题的核心,即如何在Svelte中获取数据,将其存储在哪里,如何将其传递给组件,以及如何操作数据。

1.Svelte中的异步查询

您的第一个问题是如何处理异步请求。您不能在Svelte文件的<script>部分的根级别使用await语句,这意味着以下反应语句将生成错误:

// will fail
$: data = await getData(url)

但是,您可以调用一个异步函数来处理赋值。当url更改并检索到新数据时,反应性仍然有效,并且您的组件将重新呈现:

// will work
$: updateData(url)
async function updateData(url) {
data = await getData(url)
}

以下是一个基于问题中REPL的工作示例

2.使用商店

正如您从上面的例子中看到的那样,您必须将数据传递给<Header><Chart>组件,以便在以下任一组件中使用:

<Header {data}>GitHub Lookup</Header>
<Chart {data}/>

但是,如果您想在应用程序的其他地方使用图表,该怎么办?如果您有另一个组件想要使用相同的数据,该怎么办?

显然,您不想通过&结束(除非请求本身已更改)。您还希望避免将数据作为道具在应用程序中到处传递。您将希望使数据只对这些将使用它的组件可用。

这就是商店派上用场的地方。任何组件都可以订阅存储。可写存储将允许更新其内容,而可读存储将是只读的,顾名思义。

商店不一定很复杂。以下是一个非常基本的可写存储:

import { writable } from 'svelte/store'
export const githubStore = writable(null) // initialized with a null value

然后你所要做的就是与你的商店互动。

更新应用程序组件中的商店:

import { githubStore as data } from './githubStore.js' // import the store we defined above under the name 'data'
.
.
.
async function updateData(url) {
$data = await getData(url) // using the $ shorthand to access the store (assigning a new value will update the store content)
}

使用(即订阅)组件中的存储:

import { githubStore as data } from './githubStore.js' // import the store we defined above under the name 'data'
.
.
.
// using the $ shorthand to access the store
{#each $data.items as item (item.id)}
<li><a href={item.html_url}>{item.full_name}</a> [{item.stargazers_count}⭐]</li>
{/each}

阅读此处了解有关在存储中使用$reactive语法的详细信息

现在,您的子组件已经订阅了存储数据的存储,您不再需要将该数据作为道具传递:

<Header>GitHub Lookup</Header>
<Chart />

这是上面REPL的更新版本,使用存储

3.进一步考虑

当您想开始操作或转换已放入存储的数据时,派生存储就派上了用场。更新原始存储中的数据时,派生存储将根据对原始存储的更改自动更新自身。

您还可以通过添加自己的功能和自定义方法,在提供的可读/写存储的基础上进行构建。这些都是稍微高级一点的主题,但在涉及数据操作时会派上用场。

最后,D3将提供自己的数据操作方法,因此将由您决定在Svelte中直接处理多少操作,以及将多少操作委托给D3。我可能会把所有与可视化(缩放、缩放等)相关的东西都放在D3端,而在Svelte端(或者更好的是,如果你可以访问的话,直接在后端!)进行实际的数据可视化前操作(即业务逻辑)。

最新更新