どのように私は私の静的サイトにリアルタイム検索を追加


私が走らせる側のプロジェクトの1つはResrc、私がソフトウェア開発のために役に立つか面白い資源をキュレーションするサイトです.
サイトは通常1日1回更新され、複雑なダイナミックな機能を提供しないので、私はJamstackとして知られている静的なサイトのアーキテクチャに行くことにしました.私が行った実際の技術スタックは、データベースのAirtableと静的サイトジェネレータのGatsbyです.これは、Gatsbyのデータソースプラグインシステムのために非常によく動作します.
しかし、人々はこの建築に質問する傾向があります.

How do I add a dynamic feature, such as search, to a static site?


それは可能ですが、伝統的に使用されるかもしれないものよりもツールの異なるセットが必要です.私の場合、私はすでにそれらのツールを使用しました:AirtableとNetlify.

📊 Airtableによるデータの保存と問い合わせ


Airtableはスプレッドシートのように見えるが、データベースのように振舞うサービスです.

最良の部分は、完全なAPIへのアクセスを得ることです.

APIは、私のデータ、リアルタイムの様々な分野でフルテキスト検索を実行することができます高度なフィルタリング機能を備えています.私は、私が考えたので、本当に興奮しました:現在、私はちょうど検索UIを構築して、結果を得るためにAJAXリクエストを送ります、そして、私はされます!
うーん、結構.Airtableは現在、アクセス制御機能を持っていません.つまり、フロントエンド上でAPIキーを公開すると、誰でも私のデータを削除するよう要求することができます.それは私が安全に呼ぶものではありません.
この記事がチュートリアルであることに注意してください、そうするために、私はあなたにcreate an Airtable baseadd some recordsとそれからcheck out the APIを推薦し続けます.

🔑 netlify関数でAPIキーを確保する


Netlifyは静的サイトの配備を扱うサービスです.静的サイトに役立つ多くの機能の中で、彼らはServerlessな機能を提供します.AWS Lambdaがフードの下で使われる間、あなたは複雑な実現詳細について心配する必要はありません.
私たちがServerlessな関数を使いたい理由は、彼らがAirtable APIに我々の要求をプロキシして、APIキーを隠す方法を提供するからです.フロントエンドの代わりにエアテーブルに直接リクエストを行うと、それはServerless関数に行われます.

Note: This tutorial assumes that you already created a site with a static site generator such as Gatsby, Next.js or Eleventy.


netlify関数を設定するには、まずnetlify.tomlファイルを作成する必要があります.
[build]
  functions = "functions"
APIキーを.envファイルに保存しましょう.
AIRTABLE_API_KEY=PLACEHOLDER
.envファイルがignored by Gitであることを確認してください.また、このキーをenvironment variable in Netlifyとして追加する必要があります.
次に、ファイルfunctions/search.jsを作成します.
const Airtable = require('airtable');

const AIRTABLE_API_KEY = process.env.AIRTABLE_API_KEY;
const AIRTABLE_BASE_ID = 'PLACEHOLDER'; // TODO: Replace placeholder.
const AIRTABLE_TABLE_NAME = 'PLACEHOLDER'; // TODO: Replace placeholder.
const AIRTABLE_PAGE_SIZE = 30;

const RESPONSE_HEADERS = {
  'Content-Type': 'application/json; charset=utf-8',
};

exports.handler = async function (event) {
  const { query } = event.queryStringParameters;

  if (!query) {
    return {
      statusCode: 422,
      body: JSON.stringify({ error: 'Query is required.' }),
    };
  }

  if (!AIRTABLE_API_KEY) {
    return {
      statusCode: 500,
      body: JSON.stringify({ error: 'Airtable API key is missing.' }),
    };
  }

  const base = new Airtable({ apiKey: AIRTABLE_API_KEY }).base(
    AIRTABLE_BASE_ID
  );

  const results = await base(AIRTABLE_TABLE_NAME)
    .select({
      pageSize: AIRTABLE_PAGE_SIZE,
      // TODO: Update to use your field names.
      filterByFormula: `
      OR(
        SEARCH("${query.toLowerCase()}", LOWER({Name})),
        SEARCH("${query.toLowerCase()}", LOWER({Description})),
        SEARCH("${query.toLowerCase()}", LOWER({Category})),
        SEARCH("${query.toLowerCase()}", LOWER({URL}))
      )
    `,
    })
    .firstPage()
    .catch((error) => {
      console.log(`Search error from Airtable API: ${error.message}`);
      return null;
    });

  const noResults = !Array.isArray(results) || results.length === 0;

  if (noResults) {
    return {
      statusCode: 404,
      body: JSON.stringify({ error: 'No results.' }),
    };
  }

  return {
    statusCode: 200,
    headers: RESPONSE_HEADERS,
    body: JSON.stringify({ results }),
  };
};
// TODOコメントを自分のキーとフィールドに置き換えてください.
現在、Airtable JavaScript clientNetlify CLIをインストールしましょう.
npm install airtable
npm install netlify-cli --dev
netlifyアカウントを接続します.
npx netlify login
最後に、開発サーバを起動できます.
npx netlify --command="npm run develop"
npm run developにあなたのサーバーを起動するために通常使用するコマンドで置き換えてください.
検索結果は、次の検索エンドポイントでアクセスできます

http://localhost:8888/.netlify/functions/search?query=test ⚛️ データを効率的にフェッチする


React Query驚くべきデータフェッチライブラリですが、先に行くことができますので、フロントエンドを作成するため、オプションです.たとえば、HTMLフォームを作成し、React Queryを使用して検索終了点にリクエストを送信できます.
しかし、私はこの記事のタイトルにResponseクエリを入れたので、私はどのようにResRCのためのより効率的なフェッチ戦略を実装するかを共有する義務があります.飛び込みましょう.

フェッチAPI 🔎 検索コンポーネント


コンポーネントは状態管理を標準形式で提供します:
import React, { useState } from 'react';

export default function Search() {
  const [query, setQuery] = useState('');

  const handleSubmit = (event) => {
    event.preventDefault();
    window.location.href = `/search?query=${query}`;
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        placeholder="Search..."
        aria-label="Search query"
        onChange={(event) => setQuery(event.target.value)}
        value={query}
        required
      />

      <button type="submit">Submit</button>
    </form>
  );
}
ResRCでは、ヘッダーに表示された検索フォームがあります.これは、フォームが提出されるたびに、私は/searchルートに移動するという決定をした理由です.これ
  • は、検索結果ページURLを共有することを許します.
  • は、ページ読み込み時のデータ取得を簡素化します.
  • また、単一のページのアプリではなく、クライアント側のルートナビゲーションを使用する必要があります.ギャツビーは、 と次を提供します.JSはnavigate helperを提供します.

    ユーザー外部フック ⚓️ USEearchフック


    さて、いくつかのデータを取得しましょう!サイト内の検索ページとコンポーネントを作成します
    import React, { useState, useEffect } from 'react';
    import { useQuery } from 'react-query';
    
    const SEARCH_API_ENDPOINT = '/.netlify/functions/search';
    
    const fetchSearch = async (key, query) => {
      if (!query) {
        throw new Error('Search query is required.');
      }
    
      return fetch(
        `${SEARCH_API_ENDPOINT}?query=${encodeURIComponent(query)}`
      ).then(async (response) => {
        const data = await response.json();
    
        if (response.status !== 200) {
          const error = new Error(data.error || 'Unknown error');
          error.statusCode = response.status;
          throw error;
        }
    
        return data;
      });
    };
    
    function useSearch(query) {
      return useQuery(['search', query], fetchSearch);
    }
    
    function SearchResultsPage() {
      const [query, setQuery] = useState(null);
      const { isLoading, isSuccess, isError, data, error } = useSearch(query);
    
      useEffect(() => {
        const query = new URLSearchParams(window.location.search).get('query');
        if (query) setQuery(query);
      }, []);
    
      if (isLoading) return 'Loading...';
    
      if (isError && error.statusCode === 404) return 'No results';
    
      if (isError) return error.message;
    
      if (isSuccess) {
        return (
          <ul>
            {data.results.map((result) => (
              <li key={result.id}>{JSON.stringify(result)}</li>
            ))}
          </ul>
        );
      }
    
      return null;
    }
    
    useSearchと呼ばれるカスタムフックへのデータの取り込み方法に注意してください.
    これにより、検索機能が終了しました.
  • 型にtestを入力し、Enterキーを押します.
  • ページは、/search?query=testに移動されます
  • は、/.netlify/functions/search?query=testから質問フェッチ結果を反応させます
  • の結果は、読み込み、成功、またはエラーステータスに応じてレンダリングされます.
  • ここでどんなデザインも提供していないので、データの表示方法を決めるのはあなた次第です.しかし、 のような準備された設計コンポーネントシステムを実装することによって、経験を迅速に浪費することができます.私はresrcのためにそれを使用します.

    チャクラウイ 🎁 ラッピング


    すぐに我々のリアルタイム検索スタックの異なる層を要約しましょう
    Airtableは、我々が格納したデータを問い合わせるために、全文検索APIを提供します.
  • netlify関数はAPIのリクエストをエアテーブルにプロキシし、APIキーを隠します.
  • は、キャッシュのようないくつかの機能を備えたクエリフェッチの検索結果を反応させる.
  • あなたが動けなくなるならば、 を参照すること自由に感じてください.また、常にsource code of Resrc on GitHubまたは質問やフィードバックを送信する無料です.