用Airtable, Gatsby和React构建交互式甘特图

安娜Prenzel
分享

使用Gatsby,可以很容易地将不同的数据源集成到一个应用程序中。在本文中,我们将开发一个任务管理工具,其数据取自Airtable。我们将使用React作为前端,并使用混合渲染策略。

这是一个常见的场景:你想要开发一个连接到电子表格应用程序或其他数据源的数据的应用程序。在本文中,我将展示如何使用Gatsby框架实现这种类型的应用程序。在我们的示例应用程序中,任务将从Airtable工作区,并可视化为甘特图.用户可以通过拖放来移动任务,之后所有的更改都将与Airtable同步。你可以把这个项目用作各种调度应用程序的模板。

<我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2021/11/1636866638task-table.png" alt="一个简单的任务表" loading="lazy">

你可以在我的盖茨比云站点.项目的src文件可以在我的GitHub库

建立项目

盖茨比是一个静态网站生成器。这意味着您使用React编写应用程序,Gatsby将您的代码转换为浏览器可以理解的HTML文件。这个构建过程是定期在<年代trong>服务器端与传统的web应用程序相比,HTML代码首先在用户的浏览器中在客户端组装。因此,HTML文件在服务器上是静态可用的(因此称为静态站点生成器),并且可以在请求时直接发送给客户端。这减少了用户加载应用程序的时间。

必威西盟体育网页登录SitePoint的盖茨比教程提供使用此框架开发应用程序所需的所有信息。如果您希望逐步开发我的示例应用程序,您应该从下面的概要开始。

首先,您应该下载并安装node . js.您可以通过输入来检查是否正确安装节点- v在控制台上。Node的当前版本应该显示出来:

节点- v<年代pan class="token operator">>v14.16.0

使用Node,我们还得到了npm, Node包管理器。使用这个工具,我们现在可以安装盖茨比的CLI:

npm安装- g gatsby-cli

我们已经准备好使用Gatsby CLI创建一个新项目。我把它命名为“甘特-图-盖茨比”

盖茨比新甘特图盖茨比

然后使用命令移动到项目文件夹cd gantt-chart-gatsby并使用命令构建项目盖茨比的发展.现在您可以在浏览器上打开项目的索引页http://localhost:8000.首先,你应该只看到盖茨比为我们准备的欢迎页。

在下一步中,您应该检查src项目文件夹。的子文件夹src /页包含项目各个页面的React组件。现在,这对你来说足够了index.js文件的索引页,因为在我们的示例应用程序中,我们只需要一个页面。您可以删除此文件夹中的其他文件,除了js 404.(如果有人输入了错误的地址,这可以很有用)。

如果您覆盖现有的代码,这是一个很好的起点index.js下面的代码:

进口作为反应“反应”常量IndexPage= >返回<主要<年代pan class="token operator">><标题<年代pan class="token operator">>甘特图表</标题<年代pan class="token operator">><h1<年代pan class="token operator">>欢迎我的<年代pan class="token maybe-class-name">盖茨比甘特图表</h1<年代pan class="token operator">></主要<年代pan class="token operator">>出口默认的IndexPage

您可以使用该命令再次构建项目盖茨比的发展在命令行中,并在浏览器中打开索引页。现在您应该会看到空白页,标题为“欢迎来到我的盖茨比甘特图”。

用React构建前端

索引页的第一个版本

我们将把甘特图实现为一个可重用的React组件。在下面几节详细解释该组件的实现之前,我首先想说明如何初始化它并将其嵌入到索引页中。所以我建议你不要用盖茨比的发展命令,直到我们完成组件的第一个版本。(当我们准备好了,我会让你知道!)

在这个示例项目中,我使用了“工作”和“资源”的概念。<年代trong>工作是绘制到图表单元格中的任务,可以通过拖放来移动。<年代trong>资源包含可移动作业所在行的标签。这些可以是任务的名称,但在其他用例中也可以是执行任务的人员、车辆或机器的名称。

作业和资源作为属性传递给甘特图组件。在将任务管理工具连接到Airtable之前,我们用JSON格式的硬编码测试数据填充列表:

进口作为反应“反应”进口GanttChart“. . / GanttChart”进口“. . /风格/ index.css”j<年代pan class="token operator">=id<年代pan class="token operator">:“j - 1”开始<年代pan class="token operator">:日期“2021/6/1”结束<年代pan class="token operator">:日期“2021/6/4”资源<年代pan class="token operator">:“r1”id<年代pan class="token operator">:“j2”开始<年代pan class="token operator">:日期“2021/6/4”结束<年代pan class="token operator">:日期“2021/6/13”资源<年代pan class="token operator">:“r2”id<年代pan class="token operator">::“j3”开始<年代pan class="token operator">:日期“2021/6/13”结束<年代pan class="token operator">:日期“2021/6/21”资源<年代pan class="token operator">:“r3”r<年代pan class="token operator">=id<年代pan class="token operator">:“r1”的名字<年代pan class="token operator">:“任务1”id<年代pan class="token operator">:“r2”的名字<年代pan class="token operator">:“任务2”id<年代pan class="token operator">:“r3”的名字<年代pan class="token operator">:“任务3”id<年代pan class="token operator">:“r4”的名字<年代pan class="token operator">:“Task 4”常量IndexPage= >返回<主要<年代pan class="token operator">><标题<年代pan class="token operator">>甘特图表</标题<年代pan class="token operator">><h1<年代pan class="token operator">>欢迎我的<年代pan class="token maybe-class-name">盖茨比甘特图表</h1<年代pan class="token operator">><GanttChart工作<年代pan class="token operator">=j<年代pan class="token punctuation">}资源<年代pan class="token operator">=r<年代pan class="token punctuation">}/></主要<年代pan class="token operator">>出口默认的IndexPage

用于甘特图的CSS样式

在下一步中,我们创建一个新的index.css风格文件夹中。(如果该文件夹不存在,请创建一个新文件夹风格在文件夹里src这个项目。)以下CSS设置控制甘特图的布局和外观:

身体字体类型天线<年代pan class="token punctuation">,海维提卡<年代pan class="token punctuation">,无衬线<年代pan class="token punctuation">;# gantt-container显示网格<年代pan class="token punctuation">;.gantt-row-resource背景颜色烟白颜色rgba0000.726边境1px固体<年代pan class="token color">rgb133129129text-align中心<年代pan class="token punctuation">;填充15px.gantt-row-period背景颜色烟白颜色rgba0000.726边境1px固体<年代pan class="token color">rgb133129129text-align中心<年代pan class="token punctuation">;显示网格<年代pan class="token punctuation">;grid-auto-flow列<年代pan class="token punctuation">;grid-auto-columns极大极小40px1fr.period填充10px010px0.gantt-row-item边境1px固体<年代pan class="token color">rgb214214214填充10px010px0位置相对<年代pan class="token punctuation">;背景颜色白色.job位置绝对<年代pan class="token punctuation">;高度38px5pxz - indexOne hundred.背景颜色rgb167171245光标指针<年代pan class="token punctuation">;

实现GanttChart组件

的实现GanttChart组件的详细信息。首先,我们需要一个名为GanttChart.jssrc文件夹中。的简化版本GanttChart只有一个月(2021年6月)。可以在GitHub上找到一个扩展版本,其中包含开始月份和结束月份的选择字段GanttChart_extended.js

图表的建立分为三个步骤,以函数表示initFirstRowinitSecondRow而且initGanttRows

进口反应“反应”出口GanttChart扩展反应<年代pan class="token punctuation">.组件的名字<年代pan class="token operator">=“1月”“2月”“3”“4月”“可能”“君”“7”“8月”“9”“10月”“11月”“12月”构造函数道具超级道具<年代pan class="token punctuation">)状态dateFrom<年代pan class="token operator">:日期202151dateTo<年代pan class="token operator">:日期2021530.渲染月<年代pan class="token operator">=日期状态dateFromgetFullYear状态dateFromgetMonth1grid_style<年代pan class="token operator">=“100 px fr”firstRow<年代pan class="token operator">=initFirstRow月<年代pan class="token punctuation">)secondRow<年代pan class="token operator">=initSecondRow月<年代pan class="token punctuation">)ganttRows<年代pan class="token operator">=initGanttRows月<年代pan class="token punctuation">)返回<div类名<年代pan class="token operator">=“甘特图”><div id<年代pan class="token operator">=“gantt-container”风格<年代pan class="token operator">=gridTemplateColumns<年代pan class="token operator">:grid_style<年代pan class="token punctuation">}>firstRow<年代pan class="token punctuation">}secondRow<年代pan class="token punctuation">}ganttRows<年代pan class="token punctuation">}</div<年代pan class="token operator">></div<年代pan class="token operator">>initFirstRowinitSecondRowinitGanttRows/ /辅助功能:formatDated返回d<年代pan class="token punctuation">.getFullYear+“-”+zeroPadd<年代pan class="token punctuation">.getMonth+1+“-”+zeroPadd<年代pan class="token punctuation">.获取当前日期zeroPadn返回n<年代pan class="token operator"><10?“0”+n<年代pan class="token operator">:n<年代pan class="token punctuation">;monthDiffd1<年代pan class="token punctuation">,d2个月<年代pan class="token punctuation">;个月<年代pan class="token operator">=d2<年代pan class="token punctuation">.getFullYear-d1<年代pan class="token punctuation">.getFullYear12个月<年代pan class="token operator">- =d1<年代pan class="token punctuation">.getMonth个月<年代pan class="token operator">+ =d2<年代pan class="token punctuation">.getMonth返回个月<年代pan class="token operator">< =0?0个月<年代pan class="token punctuation">;dayDiffd1<年代pan class="token punctuation">,d2diffTime<年代pan class="token operator">=数学腹肌d2<年代pan class="token operator">-d1<年代pan class="token punctuation">)diffDays<年代pan class="token operator">=数学装天花板diffTime<年代pan class="token operator">/1000606024返回diffDays<年代pan class="token punctuation">;

initFirstRow函数时,生成图表表的第一行。从上图中可以看到,第一行包含两个网格单元格。它们被生成为div,然后作为子元素插入到“gantt-container”中(参见上面的清单)。第二个div还包含当前月份的标签。

反应要求枚举中的所有元素都有一个唯一的“key”属性。这有助于优化渲染性能:

initFirstRow元素<年代pan class="token operator">=我<年代pan class="token operator">=0元素<年代pan class="token punctuation">.<div的关键<年代pan class="token operator">=“fr”+我<年代pan class="token operator">++类名称<年代pan class="token operator">=“gantt-row-resource”></div<年代pan class="token operator">>元素<年代pan class="token punctuation">.<div的关键<年代pan class="token operator">=“fr”+我<年代pan class="token operator">++类名称<年代pan class="token operator">=“gantt-row-period”><div类名<年代pan class="token operator">=“期”>的名字月<年代pan class="token punctuation">.getMonth+”“+月<年代pan class="token punctuation">.getFullYear</div<年代pan class="token operator">></div<年代pan class="token operator">>返回元素<年代pan class="token punctuation">;

控件中生成图表表的下一行initSecondRow函数。我们再次使用相同的原则:为每个表单元创建一个div。您必须确保div正确嵌套(行中的第二个div包含每个月的每一天的单独div),以便CSS Grid设置(参见index.css文件)将产生所需的布局:

initSecondRow元素<年代pan class="token operator">=我<年代pan class="token operator">=0/ /第一个div元素<年代pan class="token punctuation">.<div的关键<年代pan class="token operator">=“老”+我<年代pan class="token operator">++风格<年代pan class="token operator">=borderTop<年代pan class="token operator">:“没有”类名称<年代pan class="token operator">=“gantt-row-resource”></div<年代pan class="token operator">>天<年代pan class="token operator">=f_om<年代pan class="token operator">=日期月<年代pan class="token punctuation">)//每月的第一天l_om<年代pan class="token operator">=日期月<年代pan class="token punctuation">.getFullYear月<年代pan class="token punctuation">.getMonth+10//每月的最后一天日期<年代pan class="token operator">=日期f_om<年代pan class="token punctuation">)日期<年代pan class="token punctuation">;日期<年代pan class="token operator">< =l_om<年代pan class="token punctuation">;日期<年代pan class="token punctuation">.设置当前日期日期<年代pan class="token punctuation">.获取当前日期+1天<年代pan class="token punctuation">.<div的关键<年代pan class="token operator">=“老”+我<年代pan class="token operator">++风格<年代pan class="token operator">=borderTop<年代pan class="token operator">:“没有”类名称<年代pan class="token operator">=“gantt-row-period期”>日期<年代pan class="token punctuation">.获取当前日期</div<年代pan class="token operator">>//带子div的一行中的第二个div元素<年代pan class="token punctuation">.<div的关键<年代pan class="token operator">=“老”+我<年代pan class="token operator">++风格<年代pan class="token operator">=边境<年代pan class="token operator">:“没有”类名称<年代pan class="token operator">=“gantt-row-period”>天<年代pan class="token punctuation">}</div<年代pan class="token operator">>返回元素<年代pan class="token punctuation">;

图表表的其余行在initGanttRows函数。它们包含绘制作业的网格单元格。同样,呈现是逐行完成的:对于每一行,我们首先放置资源的名称,然后遍历每月的各个日子。每个网格单元格初始化为ChartCell组件用于指定的日期和资源。与cell_jobsList中,每个单元格被分配了需要被绘制到其中的作业(通常这是一个作业):

initGanttRows元素<年代pan class="token operator">=我<年代pan class="token operator">=0道具资源forEach资源= >元素<年代pan class="token punctuation">.<div的关键<年代pan class="token operator">=“gr”+我<年代pan class="token operator">++风格<年代pan class="token operator">=borderTop<年代pan class="token operator">:“没有”类名称<年代pan class="token operator">=“gantt-row-resource”>资源<年代pan class="token punctuation">.的名字</div<年代pan class="token operator">>细胞<年代pan class="token operator">=f_om<年代pan class="token operator">=日期月<年代pan class="token punctuation">)l_om<年代pan class="token operator">=日期月<年代pan class="token punctuation">.getFullYear月<年代pan class="token punctuation">.getMonth+10日期<年代pan class="token operator">=日期f_om<年代pan class="token punctuation">)日期<年代pan class="token punctuation">;日期<年代pan class="token operator">< =l_om<年代pan class="token punctuation">;日期<年代pan class="token punctuation">.设置当前日期日期<年代pan class="token punctuation">.获取当前日期+1cell_jobs<年代pan class="token operator">=道具工作过滤器工作= >工作<年代pan class="token punctuation">.资源= =资源<年代pan class="token punctuation">.id& &工作<年代pan class="token punctuation">.开始取得时间= =日期<年代pan class="token punctuation">.取得时间细胞<年代pan class="token punctuation">.<ChartCell关键<年代pan class="token operator">=“gr”+我<年代pan class="token operator">++资源<年代pan class="token operator">=资源<年代pan class="token punctuation">}日期<年代pan class="token operator">=日期日期<年代pan class="token punctuation">)工作<年代pan class="token operator">=cell_jobs<年代pan class="token punctuation">}/>元素<年代pan class="token punctuation">.<div的关键<年代pan class="token operator">=“gr”+我<年代pan class="token operator">++风格<年代pan class="token operator">=边境<年代pan class="token operator">:“没有”类名称<年代pan class="token operator">=“gantt-row-period”>细胞<年代pan class="token punctuation">}</div<年代pan class="token operator">>返回元素<年代pan class="token punctuation">;

的代码ChartCell组件的末尾GanttChart.js.该组件将图表的单个表格单元格呈现为div,其中包含一个或多个作业作为子元素。控件提供了用于显示作业的HTML代码getJobElement功能:

ChartCell扩展反应<年代pan class="token punctuation">.组件构造函数道具超级道具<年代pan class="token punctuation">)状态工作<年代pan class="token operator">:道具<年代pan class="token punctuation">.工作渲染jobElements<年代pan class="token operator">=道具工作地图工作= >getJobElement工作<年代pan class="token punctuation">)返回<div风格<年代pan class="token operator">=borderTop<年代pan class="token operator">:“没有”borderRight<年代pan class="token operator">:“没有”写成backgroundColor<年代pan class="token operator">:道具日期getDay= =0||道具日期getDay= =6?“烟白”“白色”类名称<年代pan class="token operator">=“gantt-row-item”>jobElements<年代pan class="token punctuation">}</div<年代pan class="token operator">>getJobElement工作d<年代pan class="token operator">=dayDiff工作<年代pan class="token punctuation">.开始工作<年代pan class="token punctuation">.结束//例如:一个持续时间为2天的作业正好覆盖了两个网格单元格,因此宽度为2*100%,我们必须将网格线的宽度加起来2px返回<div风格<年代pan class="token operator">=宽度<年代pan class="token operator">:“钙(“+d<年代pan class="token operator">*One hundred.+% ++d<年代pan class="token operator">+“px)”类名称<年代pan class="token operator">=“工作”id<年代pan class="token operator">=工作<年代pan class="token punctuation">.id关键<年代pan class="token operator">=工作<年代pan class="token punctuation">.id></div<年代pan class="token operator">>dayDiffd1<年代pan class="token punctuation">,d2diffTime<年代pan class="token operator">=数学腹肌d2<年代pan class="token operator">-d1<年代pan class="token punctuation">)diffDays<年代pan class="token operator">=数学装天花板diffTime<年代pan class="token operator">/1000606024返回diffDays<年代pan class="token punctuation">;

方法从根文件夹构建项目盖茨比的发展命令。索引页中的硬编码作业应该在甘特图中可见。它们还不能被拖放,但我们稍后会解决这个问题。

从Airtable集成数据

现在是时候将应用程序连接到Airtable了,这样我们就可以从那里导入作业和资源。首先,创建一个免费帐户Airtable.登录后,你会看到一个“Untitled Base”(见下图)。点击<年代trong>添加底色,然后<年代trong>从头开始,并为您的基地输入一个名称。我进入“任务管理器”。

<我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2021/11/1636866686adding-a-base.png" alt="增加基数" loading="lazy">

使用“作业”和“资源”表建立Airtable基础

现在你可以为你的基础定义表,按照以下步骤:

  1. 用字段定义表“Jobs”id(字段类型:文本),开始(字段类型:Date)和结束(字段类型:Date)。
  2. 用字段定义表“Resources”id(字段类型:文本)和的名字(字段类型:text)。
  3. 转到“Jobs”表,添加一个字段资源输入“链接到另一个记录”,然后选择该字段id作为表“Resource”的查找字段。

在这些步骤之后,您的表应该如下图所示。

<我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2021/11/1636866709task-manager1.png" alt="任务管理器" loading="lazy">

任务管理器

用GraphQL和Gatsby的Airtable插件从Airtable导入数据

接下来,我们希望将数据从Airtable导入到应用程序中。为此,安装插件“gatsby-source-airtable”withNPM安装——保存gatsby-source-airtable.然后,修改gatsby-config.js在你的项目文件夹中,如下表所示:

模块<年代pan class="token punctuation">.出口siteMetadata<年代pan class="token operator">:siteUrl<年代pan class="token operator">:“https://www.yourdomain.tld”标题<年代pan class="token operator">:《盖茨比甘特图》插件<年代pan class="token operator">:“gatsby-plugin-gatsby-cloud”解决<年代pan class="token operator">:“gatsby-source-airtable”选项<年代pan class="token operator">:apiKey<年代pan class="token operator">:“XXX”//可以通过env指定,参见下面并发性<年代pan class="token operator">:5//默认,参见using markdown和附件了解更多信息表<年代pan class="token operator">:baseId<年代pan class="token operator">:“多”的表<年代pan class="token operator">:“工作”baseId<年代pan class="token operator">:“多”的表<年代pan class="token operator">:“资源”

现在我们可以尝试从Airtable中获取数据。使用以下命令启动应用程序盖茨比的发展,然后在浏览器中打开GraphiQL编辑器http://localhost:8000/___graphql并将以下查询粘贴到左侧区域:

工作<年代pan class="token operator">:allAirtable过滤器<年代pan class="token operator">:表格<年代pan class="token operator">:情商<年代pan class="token operator">:“工作”数据<年代pan class="token operator">:边缘<年代pan class="token punctuation">{节点<年代pan class="token punctuation">{数据<年代pan class="token punctuation">{Id开始结束id__from_resource_资源<年代pan class="token punctuation">}recordId<年代pan class="token punctuation">}资源<年代pan class="token operator">:allAirtable过滤器<年代pan class="token operator">:表格<年代pan class="token operator">:情商<年代pan class="token operator">:“资源”排序<年代pan class="token operator">:字段<年代pan class="token operator">:data___name<年代pan class="token punctuation">]订单<年代pan class="token operator">:ASC边缘<年代pan class="token punctuation">{节点<年代pan class="token punctuation">{数据<年代pan class="token punctuation">{身份证的名字<年代pan class="token punctuation">}

单击箭头符号以运行查询。查询的结果应该出现在右侧。

<我mg decoding="async" src="https://uploads.sitepoint.com/wp-content/uploads/2021/11/1636866764query-result.png" alt="查询的结果" loading="lazy">

现在是时候删除包含作业和资源的硬编码列表了index.js.中的代码更新index.js如下面的清单所示。这里发生了什么?首先,在文件的末尾,你可以看到一个所谓的“页面查询,要求所有的工作和资源。查询的结果自动分配给数据组件的属性IndexPage.因此,数据属性将在右侧的GraphiQL编辑器中准确地存储您所看到的查询结果。我们可以用地图函数来转换工作而且资源数组转换成我们首选的格式。

尽管看起来有点麻烦,但我们必须保留这些属性recordID而且id__from_resource,由Airtable自动为所有作业创建。这是必要的,这样我们以后可以通过Airtable REST API保存对作业的更改:

进口作为反应“反应”进口useStaticQuery<年代pan class="token punctuation">,graphql<年代pan class="token punctuation">}“盖茨比”进口GanttChart“. . / GanttChart”进口“. . /风格/ index.css”/ /标记常量IndexPage数据= >j<年代pan class="token operator">=数据<年代pan class="token punctuation">.数据工作边缘地图边缘= >年代<年代pan class="token operator">=日期边缘<年代pan class="token punctuation">.节点数据开始年代<年代pan class="token punctuation">.setHours0e<年代pan class="token operator">=日期边缘<年代pan class="token punctuation">.节点数据结束e<年代pan class="token punctuation">.setHours0返回airtable_id<年代pan class="token operator">:边缘<年代pan class="token punctuation">.节点recordIdid<年代pan class="token operator">:边缘<年代pan class="token punctuation">.节点数据id开始<年代pan class="token operator">:年代<年代pan class="token punctuation">,结束<年代pan class="token operator">:e<年代pan class="token punctuation">,资源<年代pan class="token operator">:边缘<年代pan class="token punctuation">.节点数据id__from_resource_0resource_airtable_id<年代pan class="token operator">:边缘<年代pan class="token punctuation">.节点数据资源0r<年代pan class="token operator">=数据<年代pan class="token punctuation">.数据资源边缘地图边缘= >返回id<年代pan class="token operator">:边缘<年代pan class="token punctuation">.节点数据id的名字<年代pan class="token operator">:边缘<年代pan class="token punctuation">.节点数据的名字如果r<年代pan class="token operator">& &j<年代pan class="token punctuation">)返回<主要<年代pan class="token operator">><标题<年代pan class="token operator">>甘特图表</标题<年代pan class="token operator">><h1<年代pan class="token operator">>欢迎我的<年代pan class="token maybe-class-name">盖茨比甘特图表</h1<年代pan class="token operator">><GanttChart工作<年代pan class="token operator">=j<年代pan class="token punctuation">}资源<年代pan class="token operator">=r<年代pan class="token punctuation">}/></主要<年代pan class="token operator">>其他的返回<主要<年代pan class="token operator">><标题<年代pan class="token operator">>甘特图表</标题<年代pan class="token operator">><h1<年代pan class="token operator">>欢迎我的<年代pan class="token maybe-class-name">盖茨比甘特图表</h1<年代pan class="token operator">><p<年代pan class="token operator">>失踪数据<年代pan class="token spread operator">…</p<年代pan class="token operator">></主要<年代pan class="token operator">>出口常量查询<年代pan class="token operator">=graphql<年代pan class="token template-string">查询工作allAirtable<年代pan class="token punctuation">(过滤器表格情商“工作”数据边缘<年代pan class="token punctuation">{节点<年代pan class="token punctuation">{数据<年代pan class="token punctuation">{Id开始结束id__from_resource_资源<年代pan class="token punctuation">}recordId<年代pan class="token punctuation">}资源allAirtable<年代pan class="token punctuation">(过滤器表格情商“资源”排序字段data___name<年代pan class="token punctuation">]订单ASC边缘<年代pan class="token punctuation">{节点<年代pan class="token punctuation">{数据<年代pan class="token punctuation">{身份证的名字<年代pan class="token punctuation">}出口默认的IndexPage

如果您在本地使用盖茨比的发展,从Airtable中获取数据并显示在甘特图中。如果你已经建立了一个盖茨比云网站根据盖茨比教程,一旦你将代码更改推送到相关的GitHub帐户,该网站就会更新。但是,您会注意到,Airtable查询只在构建项目时执行(不管它是在本地发生还是在Gatsby Cloud站点上发生)。如果您修改了Airtable基础中的数据,则更改不会反映在甘特图中,除非您重新构建项目。这是Gatsby的服务器端呈现过程的典型情况。

在下一节中,我们将讨论如何处理数据中的更改。

实现盖茨比与Airtable的双向同步

在我们的示例中,可以在Airtable中(通过编辑表格单元格)或在Gantt图中(通过拖放)对数据进行更改。为了同步这些部分,我采用了一种混合策略,包括服务器端和客户端更新操作。

1.将更改从Airtable传输到甘特图(服务器端)

盖茨比所提供的人则远程触发服务器端构建流程。可以配置Airtable在某些事件上自动触发构建钩子(比如创建或更改记录),前提是您有专业会员资格。(您可以找到关于为此目的所必需的设置的更详细信息在这里).

2.将更改从Airtable转移到甘特图(客户端)

当应用程序在浏览器中使用时,甘特图应该动态地从Airtable加载更新(例如,以特定的时间间隔)。为了简化这个过程,我们只需要在指定的时间间隔重新下载完整的作业和资源列表。为此,我们将使用官方的Airtable API。

IndexPage组件,我们使用React的useState钩子将作业和资源设置为组件状态的列表。然后我们应用useEffect钩设置函数所处的间隔loadDataFromAirtable在组件初始化后调用:

常量IndexPage数据= >j<年代pan class="token operator">=数据<年代pan class="token punctuation">.数据工作边缘地图边缘= >r<年代pan class="token operator">=数据<年代pan class="token punctuation">.数据资源边缘地图边缘= >常量资源<年代pan class="token punctuation">,setResources<年代pan class="token punctuation">]useStater<年代pan class="token punctuation">)常量工作<年代pan class="token punctuation">,setJobs<年代pan class="token punctuation">]useStatej<年代pan class="token punctuation">)useEffect= >常量时间间隔<年代pan class="token operator">=setInterval= >jobsLoadedj= >setJobsj<年代pan class="token punctuation">)resourcesLoadedr= >setResourcesr<年代pan class="token punctuation">)loadDataFromAirtablejobsLoaded<年代pan class="token punctuation">,resourcesLoaded<年代pan class="token punctuation">)60000返回= >clearInterval时间间隔<年代pan class="token punctuation">)如果资源<年代pan class="token operator">& &工作<年代pan class="token punctuation">)返回<主要<年代pan class="token operator">><标题<年代pan class="token operator">>甘特图表</标题<年代pan class="token operator">><h1<年代pan class="token operator">>欢迎我的<年代pan class="token maybe-class-name">盖茨比甘特图表</h1<年代pan class="token operator">><GanttChart工作<年代pan class="token operator">=工作<年代pan class="token punctuation">}资源<年代pan class="token operator">=资源<年代pan class="token punctuation">}/></主要<年代pan class="token operator">>其他的返回<主要<年代pan class="token operator">><标题<年代pan class="token operator">>甘特图表</标题<年代pan class="token operator">><h1<年代pan class="token operator">>欢迎我的<年代pan class="token maybe-class-name">盖茨比甘特图表</h1<年代pan class="token operator">><p<年代pan class="token operator">>失踪数据<年代pan class="token spread operator">…</p<年代pan class="token operator">></主要<年代pan class="token operator">>

为实现loadDataFromAirtable函数的文档Airtable API.文档根据所选基础(在本例中为“Task Manager”)进行了调整。如果你点击<年代trong>工作表而且<年代trong>列表记录在左侧,您将看到获取“curl”区域中所有作业的数据的GET请求的确切结构。这个请求可以很容易地在JavaScript中使用“fetch”方法实现。

因此,为了下载所有作业和资源的数据,我们依次向Airtable执行两个异步GET请求。我屏蔽了确切的url,因为它们包含我的个人API密钥:

函数loadDataFromAirtableonJobsLoaded<年代pan class="token punctuation">,onResourcesLoadedj<年代pan class="token punctuation">,r<年代pan class="token punctuation">;url_j<年代pan class="token operator">=“XXXX”url_r<年代pan class="token operator">=“YYYY”获取url_j<年代pan class="token punctuation">,头<年代pan class="token operator">:“授权”“睡眠”然后响应= >响应<年代pan class="token punctuation">.json然后数据= >j<年代pan class="token operator">=数据<年代pan class="token punctuation">.记录地图记录= >年代<年代pan class="token operator">=日期记录<年代pan class="token punctuation">.字段开始年代<年代pan class="token punctuation">.setHours0e<年代pan class="token operator">=日期记录<年代pan class="token punctuation">.字段结束e<年代pan class="token punctuation">.setHours0返回airtable_id<年代pan class="token operator">:记录<年代pan class="token punctuation">.idid<年代pan class="token operator">:记录<年代pan class="token punctuation">.字段id开始<年代pan class="token operator">:年代<年代pan class="token punctuation">,结束<年代pan class="token operator">:e<年代pan class="token punctuation">,资源<年代pan class="token operator">:记录<年代pan class="token punctuation">.字段'id (from resource)'0resource_airtable_id<年代pan class="token operator">:记录<年代pan class="token punctuation">.字段资源0onJobsLoadedj<年代pan class="token punctuation">)获取url_r<年代pan class="token punctuation">,头<年代pan class="token operator">:“授权”“睡眠”然后响应= >响应<年代pan class="token punctuation">.json然后数据= >r<年代pan class="token operator">=数据<年代pan class="token punctuation">.记录地图记录= >返回id<年代pan class="token operator">:记录<年代pan class="token punctuation">.字段id的名字<年代pan class="token operator">:记录<年代pan class="token punctuation">.字段的名字onResourcesLoadedr<年代pan class="token punctuation">)

作为测试,您可以对Airtable基础中的作业数据进行一些更改。在给定的间隔时间之后(这里是一分钟),甘特图应该在浏览器中自动更新。

3.将更改从甘特图转移到Airtable基础(客户端)

在用户可以修改甘特图之前,我们必须首先使作业可拖动。为此,更新ChartCell组成部分如下:

ChartCell扩展反应<年代pan class="token punctuation">.组件构造函数道具超级道具<年代pan class="token punctuation">)渲染jobElements<年代pan class="token operator">=道具工作地图工作= >getJobElement工作<年代pan class="token punctuation">)dragOver电动汽车= >电动汽车<年代pan class="token punctuation">.preventDefault下降电动汽车= >电动汽车<年代pan class="token punctuation">.preventDefaultjob_id<年代pan class="token operator">=电动汽车<年代pan class="token punctuation">.dataTransfergetData“工作”道具onDropJobjob_id<年代pan class="token punctuation">,道具资源id道具日期返回<div风格<年代pan class="token operator">=borderTop<年代pan class="token operator">:“没有”borderRight<年代pan class="token operator">:“没有”写成backgroundColor<年代pan class="token operator">:道具日期getDay= =0||道具日期getDay= =6?“烟白”“白色”类名称<年代pan class="token operator">=“gantt-row-item”onDragOver<年代pan class="token operator">=dragOver<年代pan class="token punctuation">}onDrop<年代pan class="token operator">=下降<年代pan class="token punctuation">}>jobElements<年代pan class="token punctuation">}</div<年代pan class="token operator">>getJobElement工作d<年代pan class="token operator">=dayDiff工作<年代pan class="token punctuation">.开始工作<年代pan class="token punctuation">.结束返回<div风格<年代pan class="token operator">=宽度<年代pan class="token operator">:“钙(“+d<年代pan class="token operator">*One hundred.+% ++d<年代pan class="token operator">+“px)”类名称<年代pan class="token operator">=“工作”id<年代pan class="token operator">=工作<年代pan class="token punctuation">.id关键<年代pan class="token operator">=工作<年代pan class="token punctuation">.id可拖动的<年代pan class="token operator">=“真正的”onDragStart<年代pan class="token operator">=dragStart></div<年代pan class="token operator">>dragStart电动汽车电动汽车<年代pan class="token punctuation">.dataTransfersetData“工作”电动汽车<年代pan class="token punctuation">.目标iddayDiffd1<年代pan class="token punctuation">,d2diffTime<年代pan class="token operator">=数学腹肌d2<年代pan class="token operator">-d1<年代pan class="token punctuation">)diffDays<年代pan class="token operator">=数学装天花板diffTime<年代pan class="token operator">/1000606024返回diffDays<年代pan class="token punctuation">;

用JavaScript实现拖放并不是特别复杂。您必须实现事件的处理程序onDragStart(对于可拖动元素),onDragOver而且onDrop(对于掉落目标),如图所示本教程

对象上调用哪个处理程序函数onDropJob事件,该事件由下降处理程序。在initGanttRows函数,更新如下行:

细胞<年代pan class="token punctuation">.<ChartCell关键<年代pan class="token operator">=“gr”+我<年代pan class="token operator">++资源<年代pan class="token operator">=资源<年代pan class="token punctuation">}日期<年代pan class="token operator">=日期日期<年代pan class="token punctuation">)工作<年代pan class="token operator">=cell_jobs<年代pan class="token punctuation">}onDropJob<年代pan class="token operator">=dropJob/>

GanttChart组件,添加功能dropJob

dropJobid<年代pan class="token punctuation">,newResource<年代pan class="token punctuation">,newDate工作<年代pan class="token operator">=道具工作找到j= >j<年代pan class="token punctuation">.id= =id<年代pan class="token punctuation">)newJob<年代pan class="token operator">=newJob<年代pan class="token punctuation">.资源newResource<年代pan class="token punctuation">;d<年代pan class="token operator">=dayDiff工作<年代pan class="token punctuation">.开始工作<年代pan class="token punctuation">.结束结束<年代pan class="token operator">=日期newDate<年代pan class="token punctuation">)结束<年代pan class="token punctuation">.设置当前日期newDate<年代pan class="token punctuation">.获取当前日期+d<年代pan class="token punctuation">)newJob<年代pan class="token punctuation">.开始newDate<年代pan class="token punctuation">;newJob<年代pan class="token punctuation">.结束结束<年代pan class="token punctuation">;道具onUpdateJobid<年代pan class="token punctuation">,newJob<年代pan class="token punctuation">)

作业列表的实际修改是在父类中完成的IndexPage组件index.js.的方法用于创建作业列表的副本。使用拖放移动的作业根据其ID定位在列表中,并被赋予新的属性。之后的状态IndexPage组件通过调用更新setJobs.请注意,现在触发了甘特图组件的重新渲染,现在job元素出现在其新位置:

常量IndexPage数据= >updateJobid<年代pan class="token punctuation">,newJob= >new_jobs<年代pan class="token operator">=工作<年代pan class="token punctuation">.工作<年代pan class="token operator">=new_jobs<年代pan class="token punctuation">.找到j= >j<年代pan class="token punctuation">.id= =id<年代pan class="token punctuation">)工作<年代pan class="token punctuation">.资源newJob<年代pan class="token punctuation">.资源工作<年代pan class="token punctuation">.开始newJob<年代pan class="token punctuation">.开始工作<年代pan class="token punctuation">.结束newJob<年代pan class="token punctuation">.结束setJobsnew_jobs<年代pan class="token punctuation">)updateJobToAirtable工作<年代pan class="token punctuation">)如果资源<年代pan class="token operator">& &工作<年代pan class="token punctuation">)返回<主要<年代pan class="token operator">><标题<年代pan class="token operator">>甘特图表</标题<年代pan class="token operator">><h1<年代pan class="token operator">>欢迎我的<年代pan class="token maybe-class-name">盖茨比甘特图表</h1<年代pan class="token operator">><GanttChart工作<年代pan class="token operator">=工作<年代pan class="token punctuation">}资源<年代pan class="token operator">=资源<年代pan class="token punctuation">}onUpdateJob<年代pan class="token operator">=updateJob<年代pan class="token punctuation">}/></主要<年代pan class="token operator">>其他的

在最后一步中,我们必须实现updateJobToAirtable函数。我们再次遵循Airtable API文档,这次是在小节中<年代trong>更新记录

函数updateJobToAirtable工作数据<年代pan class="token operator">=记录<年代pan class="token operator">:id<年代pan class="token operator">:工作<年代pan class="token punctuation">.airtable_id字段<年代pan class="token operator">:id<年代pan class="token operator">:工作<年代pan class="token punctuation">.id开始<年代pan class="token operator">:formatDate工作<年代pan class="token punctuation">.开始结束<年代pan class="token operator">:formatDate工作<年代pan class="token punctuation">.结束资源<年代pan class="token operator">:工作<年代pan class="token punctuation">.resource_airtable_id获取“XXX”方法<年代pan class="token operator">:“补丁”头<年代pan class="token operator">:“授权”“不行”“内容类型”“application / json”身体<年代pan class="token operator">:JSONstringify数据<年代pan class="token punctuation">)

现在,您可以在甘特图中移动作业,并在Airtable基地中查看表“作业”如何实时更新。

最终的想法

本文中的简单任务管理应用程序说明,服务器端呈现也可以用于具有富客户端交互的应用程序。主要优点是初始加载时间短,因为DOM是在服务器上准备的。特别是对于具有非常复杂的用户界面的应用程序(例如,用于计划任务的仪表板),这可能是至关重要的。在客户端定期获取新数据通常不会导致重大的性能问题,因为React使用了一个复杂的算法以确定对DOM的哪些更改实际上是必要的。

盖茨比框架通过提供对服务器端呈现的无缝支持以及用于从外部源导入数据的大量插件,极大地简化了开发此类混合应用程序的过程。

Baidu