Jak načíst metadata Repo pomocí JavaScriptu přes Github API

Jak používat JavaScript Fetch API k načítání metadat (např. počet hvězdiček) pro repo z Github API.

Začínáme

Pro tento tutoriál použijeme CheatCode Next.js Boilerplate jako výchozí bod pro naši práci. Chcete-li začít, naklonujme kopii úložiště pro tento projekt:

Terminál

git clone https://github.com/cheatcode/nextjs-boilerplate.git

Dále cd do repo a nainstalujte jeho závislosti:

Terminál

cd nextjs-boilerplate && npm install

Nakonec pokračujte a spusťte vývojový server:

Terminál

npm run dev

Díky tomu jsme připraveni začít.

Vytvoření komponenty React.js pro vykreslení dat úložiště

Nejprve vytvoříme komponentu React, kde načteme a vykreslíme naše data z Github API. Pro naši komponentu použijeme vzor komponenty funkce:

/pages/index.js

import React from "react";
import StyledIndex from "./index.css";

const Index = () => {
  return (
    <StyledIndex>
      // We'll build out the core of our component here...
    </StyledIndex>
  );
};

Index.propTypes = {};

export default Index;

Protože standard, se kterým pracujeme, je založen na Next.js, abychom mohli definovat naši komponentu, musíme ji přidat do /pages adresář v kořenovém adresáři projektu. V zákulisí Next.js automaticky vytvoří trasu v naší aplikaci – v prohlížeči – která vykreslí komponentu, kterou vytvoříme (v tomto případě na http://localhost:5000/ když vytváříme /pages/index.js ).

Výše nastavujeme naši základní komponentu <Index /> a exportovat jej jako default z našeho souboru (vyžaduje Next.js). Když se podíváme na kód, začali jsme vytvořením stylizované komponenty:způsob, jak přidat styl do komponenty React dynamickým generováním komponenty wrapper – zde <StyledIndex />—that has CSS attached to it. Real quick, let's open up that /pages/index.css.js`, který se sem importuje, a přidejte styly, které budeme potřebovat později:

/pages/index.css.js

import styled from "styled-components";

export default styled.div`
  display: inline-block;
  border: 1px solid #eeeeee;
  padding: 40px;
  margin: 0 auto;
  border-radius: 3px;
  box-shadow: 0px 2px 2px 2px rgba(0, 0, 0, 0.02);

  > h4 {
    font-size: 16px;
    text-transform: uppercase;
    color: #aaaaaa;
  }

  > h4 .fa-star {
    color: #ffcc00;
  }

  > h1,
  > h2,
  > h3,
  > h4,
  > h5,
  > h6 {
    margin: 0;
  }

  > h2 {
    font-size: 48px;
    font-weight: bold;
    margin: 10px 0 5px;
  }

  > p {
    font-size: 20px;
    color: #888888;
    margin: 0;
  }

  > p > a {
    display: inline-block;
    font-size: 16px;
    color: #0099ff;
    margin-top: 10px;
  }

  > div {
    margin-top: 20px;
  }

  > div {
    display: flex;
    align-items: center;
  }

  > div img {
    width: 50px;
    height: 50px;
    border-radius: 50px;
    margin-right: 15px;
  }

  > div a {
    color: #aaaaaa;
  }

  > div h5 {
    margin: 0;
  }

  > div p {
    margin: 0;
  }
`;

Zde importujeme objekt styled který obsahuje řadu funkcí, z nichž každá představuje standardní HTML prvek. Když je funkce volána, očekává, že k prvku vrácenému funkcí bude připojen jeden řetězec JavaScriptu jako argument obsahující styly CSS.

Používáme styled.div funkce, zavolání pomocí zkrácené metody v JavaScriptu pro volání funkce, kde jediným předaným argumentem je řetězec:volání funkce, ale místo závorek okamžitě následuje dvojice zpětných zatržení. Mezi těmito backticks jsme předali nějaké CSS jako řetězec (opět, backticks jsou jen další způsob, jak vytvořit řetězec v JavaScriptu), aby nám pomohl stylovat označení, které přidáme do naší komponenty, kde vykreslíme naše Github repo data.

/pages/index.js

import React, { useState, useEffect } from "react";
import StyledIndex from "./index.css";

const Index = () => {
  const [loading, setLoading] = useState(true);
  const [repoName, setRepoName] = useState("");
  const [repoDescription, setRepoDescription] = useState("");
  const [repoOwner, setRepoOwner] = useState({
    username: "",
    url: "",
    avatar: "",
  });
  const [repoURL, setRepoURL] = useState("");
  const [repoStars, setRepoStars] = useState(0);

  if (loading) {
    return <div></div>;
  }

  return (
    <StyledIndex>
      <h4>
        <i className="fas fa-star" /> {repoStars} Stars
      </h4>
      <h2>{repoName}</h2>
      <p>{repoDescription}</p>
      <p>
        <a href={repoURL}>{repoURL}</a>
      </p>
      {repoOwner && (
        <div className="owner">
          {repoOwner?.avatar && (
            <img src={repoOwner.avatar} alt={repoOwner.username} />
          )}
          <div>
            <h5>{repoOwner.username}</h5>
            <p>
              <a href={repoOwner.url}>{repoOwner.url}</a>
            </p>
          </div>
        </div>
      )}
    </StyledIndex>
  );
};

Index.propTypes = {};

export default Index;

Vylepšení naší komponenty, protože budeme závislí na potenciálně pomalém požadavku API – v obecném smyslu; za normálních podmínek je API rychlé – data, která chceme vykreslit v naší komponentě, uvedeme do stavu.

Protože zde používáme vzor komponenty funkce (na rozdíl od vzoru založeného na třídě), použijeme useState() funkce hook k definování, nastavení a načtení našich různých hodnot stavu.

Pro naše potřeby máme šest hodnot, které chceme nastavit na stav:

  1. A loading stavu, abyste nám dali vědět, zda jsme dokončili požadavek API.
  2. repoName pro adresu URL, kterou požadujeme.
  3. repoDescription pro adresu URL, kterou požadujeme.
  4. repoOwner pro adresu URL, kterou požadujeme (skládající se z jejich uživatelského jména, adresy URL a avatara).
  5. repoURL pro adresu URL, kterou požadujeme (liší se od adresy URL API, kterou použijeme).
  6. repoStars pro adresu URL, kterou požadujeme.

Pro každou z výše uvedených možností zavoláme na číslo useState() , předáním výchozí hodnoty pro každý a předvídáním pole JavaScriptu na oplátku. V těchto polích očekáváme aktuální hodnotu našich stavových hodnot na první pozici (0 index) a funkci setter pro naše hodnoty stavu na druhé pozici (1 index).

Abychom usnadnili čtení našeho kódu, pro přístup k těmto hodnotám používáme destrukci pole JavaScriptu. To nám umožňuje současně přistupovat a přiřazovat hodnoty pole k proměnným. Zde například const [repoName, setRepoName] = useState(""); , lze přepsat jako:

const state = useState("");
const repoName = state[0];
const setRepoName = state[1];

Protože je to podrobnější – a pravděpodobně i matoucí – používáme místo toho vzor destrukčního pole JavaScript.

Níže jsou naše volání na useState() , zajistíme, že vrátíme prázdné <div></div> v případě, že naše loading hodnota stavu je aktuálně true (to zabrání zbytečnému flashování kódu HTML, kde vykreslujeme informace o našem repo před obdrželi jsme data z API).

Za předpokladu loading je nepravda, přejdeme k našemu return hodnotu, zde máme naše <StyledIndex /> komponenta, o které jsme se dozvěděli výše, obalená kolem značky, kterou použijeme k vykreslení naší komponenty (pro co jsme dříve nastavili styly). Není zde nic zvláštního, pouze jednoduché rozhraní ve stylu karty, které vykresluje naše data.

Nyní k té zábavnější části. Dále musíme přidat možnost načítat data z Github API. Dobrá zpráva:pro adresu URL, kterou chceme použít https://api.github.com/repos/<user>/<repo>, nebudeme muset provádět žádné speciální ověřovací postupy. je veřejně přístupný koncový bod API.

Použití rozhraní Fetch API k získání dat úložiště z Github API

Nyní, aby to všechno fungovalo, chceme implementovat naše volání Github API. K tomu použijeme rozhraní JavaScript Fetch API pro provádění našich požadavků HTTP. Toto API je integrováno do moderních webových prohlížečů, takže nemusíme instalovat nic extra.

/pages/index.js

import React, { useState, useEffect } from "react";
import StyledIndex from "./index.css";

const Index = () => {
  const [loading, setLoading] = useState(true);
  const [repoName, setRepoName] = useState("");
  const [repoDescription, setRepoDescription] = useState("");
  const [repoOwner, setRepoOwner] = useState({
    username: "",
    url: "",
    avatar: "",
  });
  const [repoURL, setRepoURL] = useState("");
  const [repoStars, setRepoStars] = useState(0);

  useEffect(() => {
    fetch(
      `https://api.github.com/repos/cheatcode/nodejs-server-boilerplate`
    ).then(async (response) => {
      // We'll handle the response from the Github API here...
    });
  }, []);

  if (loading) {
    return <div></div>;
  }

  return (
    <StyledIndex>
      ...
    </StyledIndex>
  );
};

Index.propTypes = {};

export default Index;

Mezi našimi hovory na číslo useState() a naše if (loading) podmíněné, přidali jsme volání useEffect() funkce háku, importovaná z react závislost v horní části našeho souboru. Tato funkce nám umožňuje spouštět libovolný kód, když se naše komponenta vykresluje, a také když se změní jakékoli závislosti, které jí řekneme, aby sledovala.

Zde je naším cílem spustit požadavek API, jakmile se naše stránka načte, a poté zkopírovat data, která získáme z odpovědi na tento požadavek, do hodnot stavu naší komponenty. Než to uděláme, uvnitř funkce zpětného volání, kterou předáme useEffect() (druhý argument [] může volitelně obsahovat seznam hodnot – např. rekvizity – které vynutí spuštění funkce zpětného volání, když se změní), nastavujeme naše volání API pomocí vestavěného fetch() metoda, kterou jsme naznačili výše.

Tomu předáme koncový bod API – označený api.github.com část – chceme, aby načtení provedlo požadavek a zpracovalo odpověď. Zde https://api.github.com/repos/cheatcode/nodejs-boilerplate nám vrátí metadata pro CheatCode Node.js Boilerplate. Chcete-li zobrazit náhled dat, která na oplátku očekáváme, navštivte adresu URL ve svém prohlížeči.

V našem kódu, abychom získali přístup k této odpovědi, protože používáme fetch() , musíme specifikovat, jak chceme na oplátku získat naše data:

/pages/index.js

import React, { useState, useEffect } from "react";
import StyledIndex from "./index.css";

const Index = () => {
  const [loading, setLoading] = useState(true);
  const [repoName, setRepoName] = useState("");
  const [repoDescription, setRepoDescription] = useState("");
  const [repoOwner, setRepoOwner] = useState({
    username: "",
    url: "",
    avatar: "",
  });
  const [repoURL, setRepoURL] = useState("");
  const [repoStars, setRepoStars] = useState(0);

  useEffect(() => {
    fetch(
      `https://api.github.com/repos/cheatcode/nodejs-server-boilerplate`
    ).then(async (response) => {
      const data = await response.json();

      // We'll copy our data over to state here...
    });
  }, []);

  if (loading) {
    return <div></div>;
  }

  return (
    <StyledIndex>
      ...
    </StyledIndex>
  );
};

Index.propTypes = {};

export default Index;

Uvnitř .then() zpětné volání jsme řetězili na fetch() (děláme to instinktivně, jak očekáváme fetch() vrátit JavaScript Promise), abychom získali zpět své tělo odpovědi jako data JSON – v tomto okamžiku objekt JavaScript – voláme na .json() funkce, kterou očekáváme na response objekt předán našemu .then() zpětné volání.

Protože toto očekáváme funkce — response.json() —abychom také vrátili příslib, používáme vzor async/wait, abychom sdělili JavaScriptu „v tomto kontextu očekáváme použití await prohlášení." Prohlásíme to přidáním klíčového slova async do vnějšího nadřazeného oboru (v tomto případě funkce předána do .then() ), kde je naše await bude použito prohlášení. To je vyžadováno, protože pokud tak neučiníme, JavaScript vyvolá chybu běhu programu .

S tím nyní v našem const data proměnnou, měli bychom mít data zpět pro naše repo. Přidejme to ke stavu:

/pages/index.js

import React, { useState, useEffect } from "react";
import StyledIndex from "./index.css";

const Index = () => {
  const [loading, setLoading] = useState(true);
  const [repoName, setRepoName] = useState("");
  const [repoDescription, setRepoDescription] = useState("");
  const [repoOwner, setRepoOwner] = useState({
    username: "",
    url: "",
    avatar: "",
  });
  const [repoURL, setRepoURL] = useState("");
  const [repoStars, setRepoStars] = useState(0);

  useEffect(() => {
    fetch(
      `https://api.github.com/repos/cheatcode/nodejs-server-boilerplate`
    ).then(async (response) => {
      const data = await response.json();

      if (data && data.name) {
        setRepoName(data.name);
      }

      if (data && data.description) {
        setRepoDescription(data.description);
      }

      if (data && data.owner) {
        setRepoOwner({
          username: data?.owner?.login,
          url: data?.owner?.url,
          avatar: data?.owner?.avatar_url,
        });
      }

      if (data && data.html_url) {
        setRepoURL(data.html_url);
      }

      if (data && data.stargazers_count) {
        setRepoStars(data.stargazers_count);
      }

      setLoading(false);
    });
  }, []);

  if (loading) {
    return <div></div>;
  }

  return (
    <StyledIndex>
      ...
    </StyledIndex>
  );
};

Index.propTypes = {};

export default Index;

Zde pomocí našeho set funkce, které jsme obdrželi, když jsme dříve definovali naše stavové hodnoty, zapíšeme řadu if prohlášení, z nichž každý zajišťuje, že jsme udělali ve skutečnosti získat zpět data z Github a že každá z hodnot, které potřebujeme, je přítomna v této odpovědi. Pokud ano, zavoláme příslušné set funkce – např. setRepoName() —předání odpovídající hodnoty z objektu odpovědi, který chceme vykreslit na obrazovce.

Děláme to pro každou nastavenou stavovou proměnnou, přičemž lichý muž je setRepoOwner kterým je předán objekt obsahující tři vlastnosti (na rozdíl od jedné přímo předané hodnoty).

S tím, za předpokladu, že vše funguje dobře a Github API je k dispozici, měli bychom vidět naše repo data vykreslená v prohlížeči:

Zkuste zaměnit adresu URL, kterou jsme předali, za své vlastní veřejné úložiště a uvidíte, jak se vykresluje v prohlížeči!

Zabalení

V tomto tutoriálu jsme se naučili, jak získat přístup k veřejným metadatům pro Github repo pomocí Github JavaScript API. Naučili jsme se, jak definovat komponentu React.js v Next.js, což nám dává způsob, jak načíst data z Github API a také je vykreslit na obrazovce (a upravit je pomocí stylizovaných komponent).

Nakonec jsme se naučili, jak provést požadavek HTTP pomocí JavaScriptu fetch() API a také to, jak zkopírovat data z požadavku HTTP do stavu naší komponenty a dynamicky je vykreslit na obrazovce.