建立本身的新冠病毒疫情跟蹤器(Node.js+React+TS)

做者:Krasimir Tsonev

翻譯:瘋狂的技術宅javascript

原文:https://krasimirtsonev.com/bl...html

未經容許嚴禁轉載前端

image.png

數據

如今,網絡上有數百個新冠疫情跟蹤器。首先我想知道他們把數據放在了哪裏。通過研究,很快肯定了兩個主要來源。我最初使用了其中的一個。那就是約翰·霍普金斯大學。他們在 GitHub上發佈了一些有用的csv文件。可是,那裏的數據天天僅更新一次,因此我開始尋找一些實時服務。我找到了 TheVirusTracker。我最終使用了他們的API。他們有每一個國家的摘要,但還有時間表。這對我來講更有趣。我沒有找到有關請求限制的任何信息,並且彷佛沒有任何限制信息。java

結構

TheVirusTracker 支持 CORS 請求,所以能夠將應用構建爲徹底在瀏覽器中工做的靜態頁面。可是,我走了另外一條路。如上所述,我最初用的是霍普金斯大學的數據,該數據位於 GitHub上。因此我須要從那裏拉取它。最可靠的方法是使用 GitHub 的 contents 端點。他們全部端點的速率限制爲每小時 60 個請求,爲了增長請求數量,須要使用我的訪問 token。此類 token 不該被公開共享。因此我不得不寫一些後端代碼。node

image.png

個人客戶端代碼正在向 Node.js 進程發出請求。該過程將會獲取數據,而後對其進行規範化並返回。後來我更改了數據源,但出於如下三個緣由決定保留這個處理流程:react

  • 我有一個至關不錯的用於標準化和緩存數據的層。幾乎老是有須要轉換數據的需求。不管如何,我都會有這樣的代碼,因此爲何不將其放在後端,讓客戶端去使用呢。遠程 API 是公共的和免費的,所以,我不該對請求進行從新請求。爲了提供高流量,我須要一個緩存層。解決此要求的最基本的方法是實現一個簡單的內存緩存。沒有服務器,這是不可能的。
  • 我已經花費時間編寫了一個服務器,不想放棄這項工做。
  • 到目前爲止,個人代碼公開了三個端點。我想與其餘開發人員共享這些內容,並讓其餘人使用規範化和緩存。

幾個小時後,個人項目結構變爲git

image.png

前端

作這個項目的一個緣由是提升個人 React 和 TypeScript 技能。我已經用這兩種出色的技術建立了一些項目,而且出現了一種安裝模式。在某個時候,我將必要的配置分組到一個名爲 beginning 的程序包中(你能夠在這裏閱讀更多信息 "Webpack/TypeScript/React starter kit as of 2020" )。所以,我建立了一個空文件夾並運行:程序員

npx beginning && yarn

這就建立了一個帶有 TypeScript 支持的簡單 React 應用。github

React 生態系統

React 應用自己並非什麼特別的東西。由於這是一個小項目,因此我不須要任何狀態管理。一切都只是一個帶有幾個 hook 的 <App> 組件。面試

我用 recharts 構建的圖表。使用了它的 <LineChart> 組件:

<LineChart width={900} height={400} data={graphData}>
  <XAxis dataKey="date" interval="preserveStartEnd" />
  <YAxis />
  <CartesianGrid />
  <Tooltip />
  <Legend formatter={(item, entry, idx) => data[idx as number].country} />
    <Line
      key={key}
      dot={false}
      type="monotone"
      dataKey={key}
      strokeWidth={3}
      stroke={color}
      activeDot={{ r: 5 }}
      legendType="circle"
    />
</LineChart>

結果以下:

image.png

大部分疫情跟蹤器都沒法按國家/地區過濾數據。一般,此類應用會渲染一大片數據,顯然很難過濾信息。我但願本身的跟蹤器具備這種過濾功能。我用了另外一個流行的軟件包 react-tag-autocomplete。它提供了用於管理標籤的輸入字段。這裏的標籤是國家名稱。

export default function Builder({ countries, data }: BuilderProps) {
  const [tags, setTags] = useState<Tag[]>(getTags(countries, data));
  const [suggestions, setSuggestions] = useState(getSuggestions(countries));

  function handleDelete(i: number) {
    const t = tags.slice(0);
    t.splice(i, 1);
    setTags(t);
  }
  function handleAddition(tag: Tag) {
    setTags([...tags, tag]);
  }

  return (
    <>
      <ReactTags
        tags={tags}
        suggestions={suggestions}
        handleDelete={handleDelete}
        handleAddition={handleAddition}
        placeholder="Add a country"
      />
      {tags.length > 0 && (
        <Link href={`https://c19stats.now.sh?countries=${tags.map(t => t.name).join(',')}`}>
          Click here to see stats for {tags.map(t => t.name)}
        </Link>
      )}
    </>
  );
}

爲了簡化起見,我決定生成一個連接,而不是當即向 API 發出新請求。這樣,用戶將擁有一個可共享的 URL。

image.png

該應用的其他部分是幾個支持樣式的組件,一些輸入內容和一個用於請求後端的小型數據層。全部代碼都發布在了 github.com/krasimir/covid-19-stats 上。

後端

首先,我想說 Zeit 做爲平臺是如此的使人愉快。一切都進行得如此順利。幾分鐘後,個人網頁在 Web 上的工做由Node.js 後端驅動。

我從如下 now.json 文件開始:

{
  "version": 2,
  "builds": [
    { "src": "public/*.*", "use": "@now/static" },
    { "src": "api/*.js", "use": "@now/node" }
  ],
  "routes": [
    { "src": "/api/countries", "dest": "/api/countries.js" },
    { "src": "/api", "dest": "/api/index.js" },
    { "src": "/(.*)", "dest": "/public/$1" }
  ]
}

public 文件夾包含一些靜態文件,例如個人 index.html 和生成的 JavaScript bundle。 api 目錄下的全部內容都是 lambda 函數。例如,在 https://c19stats.now.sh/api/c... 後面,我有

const countries = require('./countries.json');

function JSONResponse(res, data, status = 200) {
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.statusCode = status;
  res.end(JSON.stringify(data));
}

module.exports = async function(req, res) {
  JSONResponse(res, countries);
};

爲了訪問 TheVirusTracker 的遠程服務器,我使用了 superagent。這沒有什麼不尋常的地方,但能讓我方便的粘貼我「驚人」的緩存邏輯:

const memCache = {
  lastUpdate: null,
  data: null,
};

const CACHE_TTL = 20;

function getData(noCache) {
  if (memCache.data && memCache.lastUpdate && typeof noCache === 'undefined') {
    const now = new Date();
    const diff = (now.getTime() - memCache.lastUpdate) / 1000 / 60;
    if (diff < CACHE_TTL) {
      return Promise.resolve(memCache.data);
    }
  }
  // normalization of the data
}

咱們首先檢查是否存在緩存。 memCache 對象的 data 字段保存數據的規範化版本,所以能夠直接將其返回(注意 Promise.resolve 調用)。其次,若是有緩存的數據,咱們將檢查自上次更新以來的分鐘數。在這裏,咱們必須澄清文件的全局做用域中保留的全部內容都將保留。固然,若是我部署了新版本的 lambda 或出於某種緣由從新啓動了該進程,則緩存將被清除。可是我對此徹底滿意。這樣作的目的是避免不斷向遠端發出請求。說實話,它的效果很好。 https://c19stats.now.sh/ 有時會花費更多時間來加載數據,可是結果頁面刷新很快。

建立你本身的新冠疫情追蹤器

你能夠隨時使用 https://c19stats.now.sh/ 上的某些端點。

或者,你能夠直接使用 thevirustracker.com/api 的 API。不過若是須要緩存數據的話,則必須本身實現。其他的全由你本身決定。 https://c19stats.now.sh/ 的全部代碼都是開源的,可在 github.com/krasimir/covid-19-stats 得到。 。

😷戴好口罩,保證安全的編碼! 😷


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索