나의 개발일지

[React/TypeScript] 최종프로젝트 - Mango(환경오염 줄이기 / 지구 살리기 프로젝트!) (진행 중) - NavLink과 Button의 중첩 충돌 / Firebase 검색 기능 구현 / Firebase의 한계 본문

과제 및 팀프로젝트

[React/TypeScript] 최종프로젝트 - Mango(환경오염 줄이기 / 지구 살리기 프로젝트!) (진행 중) - NavLink과 Button의 중첩 충돌 / Firebase 검색 기능 구현 / Firebase의 한계

heew0n 2024. 1. 24. 23:40

 

중간 발표 후, 

검색 기능이 꼭 필요하다고 느꼈다

main page에서 검색을 하면 searchPage로 이동하여 검색 결과를 보여줄 예정이다.

 

 

검색이라는 버튼을 누르면 searchPage로 이동을 해야 하는데

반짝하고 이동했다가 다시 돌아왔다.

 

import React, { useState } from 'react';
import { collection, getDocs, query, where } from 'firebase/firestore';
import { db } from '../shared/firebase';
import { NavLink } from 'react-router-dom';

function Search() {
  const [searchTerm, setSearchTerm] = useState('');
  const searchPosts = async (post: string) => {
    const postsRef = collection(db, 'posts');
    const q = query(postsRef, where('hashtags', 'array-contains', searchTerm));
    const querySnapshot = await getDocs(q);
    querySnapshot.forEach((doc) => {
      console.log(doc.id, ' => ', doc.data());
    });
  };
  return (
    <>
      <input type="text" value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} placeholder="검색" />
      <NavLink to="/SearchPage">
        <button onClick={() => searchPosts(searchTerm)}>Search</button>
      </NavLink>
    </>
  );
}

export default Search;

 

 

문제는 NavLink와 button이 중첩되었기 때문이었다. button의 onClick 이벤트와 NavLink의 링크 이동이

동시에 발생하려고 해서 충돌이 일어났다.

충돌을 해결하기 위해 NavLink 대신 useNavigate를 사용했다

 

 

 

 

여기서 NavLink와 useNavigate에 대한 속성에 대해 다시 짚고 넘어가야 할 것 같다 

 

 

NavLink는 특수한 종류의 '링크' 컴포넌트로, 사용자가 현재 위치한 URL에 따라 스타일을 적용할 수 있다.

이는 웹사이트 네비게이션 메뉴에 사용되는 링크에서 주로 활용되며, 사용자가 현재 어떤 페이지에 있는지 시각적으로 표시하는 데에유용하다. NavLink는 클릭하면 연결된 경로로 이동하는 기능을 제공한다.

 

useNavigate는 React Router v6에 도입된 Hook으로, 프로그래밍 방식으로 라우팅을 수행할 수 있다. 

사용자의 특성 상호작용에 응답하여 동적으로 페이지를 전환하거나 리디렉션을 할 수 있다. 

예를 들어, 사용자가 양식을 제출한 후에 특정 페이지로 리디렉션하거나, 로그인 후에 사용자가 홈페이지로 이동시키는 등의 동작을 구현할 때 사용한다.

 

따라서, NavLink는 주로 정적인 내비게이션 링크를 생성하는 데 사용되며, useNavigate는 동적으로 페이지를 전환하거나 리디렉션하는 데 사용된다.

 

 

 

 

 

수정된 코드

 

function Search() {
  const [searchTerm, setSearchTerm] = useState('');
  const navigate = useNavigate();
  const searchPosts = async (post: string) => {
    const postsRef = collection(db, 'posts');
    const q = query(postsRef, where('hashtags', 'array-contains', searchTerm));
    const querySnapshot = await getDocs(q);
   
    querySnapshot.forEach((doc) => {
      console.log(doc.id, ' => ', doc.data());
    });
    navigate('/searchPage');
  };
  return (
    <>
      <input type="text" value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} placeholder="검색" />
      <button onClick={() => searchPosts(searchTerm)}>Search</button>
    </>
  );
}

export default Search;

 

 

 

 

posts 컬렉션의 hashtags 필드에 대한 키워드를 검색했을 때 콘솔에 잘 찍히는 것을 확인할 수 있다.

 

 

 

 

 

 

 

Firebase의 한계

 

하지만, 문제가 더 생겼다.

나는 hashtags 뿐만 아니라 title, content 필드 내용도 검색하고 싶었다.

하지만 파이어베이스는 각 필드에 대해 개별 쿼리를 수행하여 결과를 얻어야 한다.

이것은 NoSQL 데이터베이스이기 때문에 전통적인 SQL 데이터베이스에서 제공하는 복잡한 쿼리 기능들을 지원하지 않기 때문이다.

 

검색해보니까 각 필드에 대해 별도의 쿼리를 수행하고, Promise.all을 사용하여 모든 쿼리의 결과가 도착할 때까지 기다린 후,  모든 결과를 하나의 배열로 합치는 방법도 있는데, 한번에 많은 쿼리를 수행하기 때문에 성능에 영향을 줄 수 있다.

 

그래서 Algolia 같은 검색 서비스를 사용하는 방법도 있다. Firestore 데이터베이스와 별도의 검색 인덱스를 유지하여, 

복잡한 검색 기능이 가능하다.

하지만 Algolia를 사용할지 말지는 팀원들과 상의하여 사용해야 할 것 같다.

아예 해시태그만 검색이 가능하거나, 해시태그 말고 내용에 대해 검색을 해도 될 것 같다.