정적 사이트에 실시간 검색 추가 방법

내가 운영하는 보조 프로젝트는 Resrc, 내가 소프트웨어 개발을 위해 유용하거나 재미있는 자원을 기획하는 사이트이다.
사이트는 일반적으로 매일 한 번씩 업데이트되고 복잡한 동적 기능을 제공하지 않기 때문에 정적 사이트 구조를 사용하기로 결정했습니다Jamstack.내가 사용하는 실제 기술 창고는 데이터베이스Airtable와 정적 사이트 생성기Gatsby이다.Gatsby의 데이터 소스 플러그인 시스템은 구축할 때 Airtable에서 쉽게 데이터를 추출할 수 있기 때문에 이 작업은 매우 좋다.
그러나 사람들은 이런 구조를 의심하는 경향이 있다...

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


이것은 가능하지만, 전통적인 도구와는 다른 도구가 필요하다.나로서는 이미 이 도구들을 사용했다. Airtable와 Netlify.

📊 Airtable을 사용하여 데이터 저장 및 조회


Airtable는 전자 표처럼 보이지만 데이터베이스처럼 행동하는 서비스다.

가장 좋은 부분은 전체 API에 액세스할 수 있다는 것입니다.

API는 고급 필터링 기능을 통해 실시간으로 내 데이터의 각 필드에 대해 전체 텍스트 검색을 수행할 수 있습니다.나는 정말 흥분했다. 왜냐하면 나는 지금 검색 UI를 구축하고 aax 요청을 보내서 결과를 얻으면 완성할 수 있다고 생각했기 때문이다.
응, 완전히 그렇지는 않아.Airtable에는 현재 액세스 제어 기능이 없습니다. 이것은 만약에 제가 전방에 API 키를 공개했다면 누구든지 제 데이터를 삭제해 달라는 요청을 제출할 수 있다는 것을 의미합니다.이것은 결코 내가 말한 안전이 아니다.
본고는 하나의 강좌로 삼기 위해서입니다. 따라서 계속하기 위해서, 저는 당신create an Airtable base, add some records, 그리고 check out the API을 건의합니다.

🔑 Netlify 함수를 사용하여 API 키 보호


Netlify는 정적 사이트 배포를 처리하는 서비스입니다.정적 사이트에 유용한 많은 기능 중에서 그들은 서버 기능이 없다.AWS Lambda는 백그라운드에서 사용되지만 복잡한 디테일을 걱정할 필요가 없습니다.
우리가 서버 없는 함수를 사용하고자 하는 이유는 요청을 Airtable API에 에이전트하는 방법을 제공하여 API 키를 숨겼기 때문이다.프런트엔드에서 Airtable에 직접 요청하지 않고 서버 기능 없음에 요청합니다.

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 쿼리를 사용하여 효율적으로 데이터 가져오기


React Query는 놀라운 데이터 획득 라이브러리이지만, 당신이 좋아하는 전단을 계속 만들 수 있기 때문에 선택할 수 있습니다.예를 들어, HTML 양식을 만들고 Fetch API 를 사용하여 검색 끝에 요청을 보낼 수 있습니다.
그러나, 나는React 조회를 본고의 제목에 넣기 때문에, 나는Resrc를 위해 더욱 효율적인 캡처 전략을 실현하는 방법을 공유할 의무가 있다.시작합시다.

🔎 구성 요소 검색


이 구성 요소는 표준 상태 관리 테이블을 제공해야 합니다.
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을 공유할 수 있습니다.
  • 페이지가 불러오는 데이터 획득을 간소화합니다.
  • 또한 한 페이지 응용 프로그램에서 클라이언트 노선 내비게이션을 사용해야 합니다.개츠비는 하나navigate helper와 다음을 제공했다.js는 하나useRouter hook를 제공했다.

    ⚓️ useSearch 연결


    자, 이제 데이터를 좀 가져봅시다!사이트에서 검색 페이지와 구성 요소를 만들려면 다음과 같이 하십시오.
    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
  • React 쿼리 결과/.netlify/functions/search?query=test
  • 로드, 성공 또는 오류 상태에 따라 결과가 표시됩니다.
  • 주의해 주십시오. 저는 여기에서 어떠한 설계도 제공하지 않았기 때문에, 당신이 어떻게 데이터를 가장 잘 표시할 것인지를 결정합니다.그러나 기존의 디자인 구성 요소 시스템(예를 들어 Chakra UI을 실현하여 체험을 신속하게 미화할 수 있습니다.Resrc에 사용합니다.

    🎁 끝내다


    실시간 검색 스택의 다양한 계층을 빠르게 살펴보겠습니다.
  • Airtable은 저장된 데이터를 조회하기 위한 전문 검색 API를 제공합니다.
  • Netlify 함수는 우리의 API 요청을 Airtable로 에이전트하고 API 키를 숨깁니다.
  • React 쿼리는 캐시와 같은 추가 기능을 통해 검색 결과를 가져옵니다.
  • 렉이 걸리면 언제든지 참고하세요source code of Resrc on GitHub.언제든지 저에게 an email 또는 질문이나 피드백을 보내주실 수 있습니다.

    좋은 웹페이지 즐겨찾기