본문 바로가기

Libraries/React

[React] Filter (2) 검색창, 검색어, 검색 필터 기능 구현 (검색창 만들기)

728x90

 

검색 필터 기능을 구현해보자!

 

 

 

 

 만들 예제의 완성본 

 

1. 가게 이름을 검색하면 해당 검색어와 일치하는 가게가 필터 돼서 뜬다.

2. 해당하는 가게가 없을 경우 "검색 결과가 없습니다."가 뜬다.

 

 

 

 


 

 

 구현 코드 

 

 

 List.jsx  (리스트 페이지) 

import React, {useState} from "react";
import styles from "./List.module.css";
import ListSearch from "../../components/ListSearch/ListSearch";
import {data} from "../../const/data";
import {ListBox} from "../../components/ListBox/ListBox";


const List = () => {
  const [searchTerm, setSearchTerm] = useState(""); // 검색창 상태 관리

  // 타이틀 포함한것만 필터
  const filteredData = data.filter((item) => item.title.toLowerCase().includes(searchTerm.toLowerCase())); 
  // filter메서드는 제공된 함수에 의해 구현된 테스트를 통과한 모든 요소가 포함된 새 배열을 만든다.
  // 필터 함수의 조건이 (title에 있는 글자를 포함하는 것이) true인 경우 해당 요소가 배열에 들어간다.


  // state를 업데이트 해주는 함수
  const onSearch = (term) =>{
    setSearchTerm(term)
  }


  return (
    <>
      <div className={styles["list-component-container"]}>
        <ListSearch searchTerm={searchTerm} onSearch={onSearch} />
      </div>
      
      <section className={styles["list-list-container"]}>
      
        {filteredData && filteredData.length > 0 ? (
          <div className={styles["list-list-box-container"]}>
            {filteredData.map((el) => {
              // title에 해당하는 배열을 map 돌림
              return <ListBox key={el.id} {...el} />;
            })}
          </div>
        ) : (
          <span className={styles["list-no-search-result"]}>검색 결과가 없습니다.</span>
        )}
        
      </section>
      
    </>
  );
};

export default List;

 

 

 ListSearch.jsx  (검색창 컴포넌트) 

import styles from "./ListSearch.module.css";
import Magnifier from "../../assets/magnifier.png";

const ListSearch = ({onSearch, searchTerm}) => {

  const handleInputChange = (event) => {
    const term = event.target.value; // term은 입력하는 글자
    onSearch(term);   // 검색하는 글자(term)로 실시간으로 상태를 업데이트
  };

  return (
    <div className={styles["list-search-container"]}>
      <div className={styles["list-search-img-container"]}>
        <a href="#">
          <img src={Magnifier} alt="돋보기" />
        </a>
      </div>
      <input className={styles["list-search-input-container"]} placeholder="검색어를 입력해 주세요." maxLength={20} value={searchTerm} onChange={handleInputChange} />
    </div>
  );
};

export default ListSearch;

 

 


 

 

 코드 설명 

 

 

 1. List.jsx (리스트페이지)에서 useState를 써서 검색창의 상태를 관리한다. 

 const [searchTerm, setSearchTerm] = useState("");

 

 

 2.  List.jsx (리스트페이지)에서 seachTerm의 상태를 업데이트 해주는 onSearch 함수를 만든다. 

 const onSearch = (term) =>{
    setSearchTerm(term)
  }

 

 

 3. ListSearch.jsx (검색창 컴포넌트)에 상태와 함수를 props로 전달한다. 

<ListSearch searchTerm={searchTerm} setSearchTerm={setSearchTerm} onSearch={onSearch} />

 

 

 4.  ListSearch.jsx (검색창 컴포넌트)에서 props를 전달 받는다. 

const ListSearch = ({onSearch, searchTerm}) => {
···

 

 

 5. ListSearch.jsx (검색창 컴포넌트)에서 검색창에서의 사용자의 입력값을 받아서 상태를 실시간으로 업데이트하는 handleInputChange 함수를 만든다. 

  const handleInputChange = (event) => {
    const term = event.target.value; // term은 입력하는 글자
    onSearch(term);   // 검색하는 글자(term)로 실시간으로 상태를 업데이트
  };

 

 

 6. ListSearch.jsx (검색창 컴포넌트)에서 
 <input>의 value 값으로 searchTerm (state)를 달고, 
 <input>의 onChange이벤트로 handleInputChange 함수를 단다. 

<input className={styles["list-search-input-container"]} placeholder="검색어를 입력해 주세요." maxLength={20} value={searchTerm} onChange={handleInputChange} />

 

 

 7. List.jsx(페이지) 에서 title을 포함하는 단어만 필터해주는 filteredData 변수를 만든다. 

*참고) 여기서 data는 음식점 정보를 담은 배열 (더미데이터)이며, title은 음식점 이름이다. 

const filteredData = data.filter((item) => item.title.toLowerCase().includes(searchTerm.toLowerCase()));

 // filter메서드는 제공된 함수에 의해 구현된 테스트를 통과한 모든 요소가 포함된 새 배열을 만든다.
 // 필터 함수의 조건이 (title에 있는 글자를 포함하는 것이) true인 경우 해당 요소가 배열에 들어간다.

 

 

 8. List.jsx(페이지)에서 filteredData(필터된 배열)을 <ListBox /> 컴포넌트에다가 map을 돌린다. 

 이렇게 하면 필터된 배열만 리스트에 뜨게 된다. 

<div className={styles["list-list-box-container"]}>
 {filteredData.map((el) => {
 return <ListBox key={el.id} {...el} />;
 })}
</div>

 

  *참고)  ListBox.jsx 컴포넌트 코드 

import styles from "./ListBox.module.css";
import Like from "../../assets/detail/purple-thumb.png";
import Jjim from "../../assets/detail/red-heart.png";
import {useNavigate} from "react-router-dom";

export const ListBox = (props) => {
  const navigate = useNavigate();

  return (
    <>
      <button
        onClick={() => {
          navigate(`/DetailMenu/${props.id}`);
        }}
        className={styles["list-box-container"]}
      >
        <div className={styles["list-box-inner-container"]}>
          <span className={styles["list-box-title"]}>{props.title}</span>

          <div className={styles["list-box-like-jjim-container"]}>
            <div className={styles["list-box-jjim"]}>
              <img src={Jjim} alt="찜 아이콘" style={{position: "absolute", top: "0px", width: "23px", height: "23px"}} /> <span className={styles["list-box-jjim-number"]}> {props.jjim}</span>
            </div>
            <div className={styles["list-box-like"]}>
              <img src={Like} alt="좋아요 아이콘" style={{position: "absolute", top: "-1px", width: "24px", height: "24px"}} />
              <span className={styles["list-box-like-number"]}> {props.like}</span>
            </div>
          </div>

          <span className={`${styles["list-box-runtime"]} ${props.runTime === "영업 준비 중" ? styles["ready"] : ""} `}> {props.runTime}</span>
          <span className={styles["list-box-intro"]}>{props.intro}</span>
          <span className={styles["list-box-address-brief"]}>{props.addressBrief}</span>
          <img className={styles["list-box-img1"]} src={props.src1} />
          <img className={styles["list-box-img2"]} src={props.src2} />
          <img className={styles["list-box-img3"]} src={props.src3} />
        </div>
      </button>
    </>
  );
};

 

 

 9. "검색 결과가 없습니다"를 뜨게 하기 위해서 삼항연산자를 이용한다. 

filteredData가 1개 이상이면, 리스트가 뜨게하고,
그게 아니면 "검색 결과가 없습니다."가 뜨게 한다.

{filteredData && filteredData.length > 0 ? (
 <div className={styles["list-list-box-container"]}>
  {filteredData.map((el) => {
    return <ListBox key={el.id} {...el} />;
  })}
 </div> 
) : (
  <span className={styles["list-no-search-result"]}>검색 결과가 없습니다.</span> 
)}

 

 

 

 

 10. 완성본 

 

 

 

 

최신순, 오래된순 등등 필터링에 대해 궁금하시다면 아래의 게시글을 참고해주세요! 

 

https://dev-ini.tistory.com/103

 

[React] 리액트에서 필터(filter)기능 구현, 최신순/오래된순 등등 필터링

리액트에서 필터 기능을 구현해보자! 만들 예제의 완성본 1. 최신순/오래된순 필터 만들기 1. 컴포넌트를 만든다. DiaryList.js import { useState } from "react"; const ControlMenu = ({value, onChange, optionList}) => { //

dev-ini.tistory.com

 

728x90