FrontEnd/기능구현

서치박스 (SearchBox - React)

3일마다 작심3일 2021. 12. 24. 08:16

서치박스란?

서치박스는 인풋창 클릭 시 dropdown으로 아이템이 리스트형태로 나오며
input에 타이핑을하여 아이템을 쉽게 찾을 수 있게 만들어주는 기법(?) 이다.

 

 

 

sarch.test.js

describe("show Test", () => {
  it("should show first", () => {
    const datas = ["first", "second", "third", "four", "five"];
    const inputWord = "first";
    const expected = ["first"];
    expect(searchWords(datas, inputWord)).toEqual(expected);
  });

  it("should show firstWords f", () => {
    const datas = ["first", "second", "third", "four", "five"];
    const inputWord = "f";
    const expected = ["first", "four", "five"];
    expect(searchWords(datas, inputWord)).toEqual(expected);
  });

  it("should show firstWords e", () => {
    const datas = ["first", "second", "third", "four", "five"];
    const inputWord = "s";
    const expected = ["second"];
    expect(searchWords(datas, inputWord)).toEqual(expected);
  });

  const searchWords = (datas, inputWord) => {
    return datas.filter((word) => !word.search(inputWord));
  };
});

해당 코드는 search에 필요한 테스트들입니다.

 

첫번째 글자가 입력한 값인 inputWord와 매칭되는 것을 filter함수를 이용해 배열을 다시 만들어주는 방식으로 진행했습니다.

 

PSearch.js

import React, { useState } from 'react'
import Search from '../components/Search';

const PSearch = () => {
    const initialDatas = require("../json/SearchDatas.json");
    const [ input, setInput ] = useState('');
    const [ datas, setDatas ] = useState(initialDatas);

    const onChange = (e) => {
        const searchWords = (datas, inputWord) => {
            return datas.filter((word) => !word.search(inputWord));
        };
        setInput(e.target.value);
        setDatas(searchWords(initialDatas, e.target.value))
    }

    return (
        <Search datas={datas} input={input} onChange={onChange}/>
    )
}

export default PSearch

우선 보여줄 데이터인 initialDatas를 받아주고

onChange함수를 이용해 input에 값이 들어올때마다 filter함수와 테스트에 사용했던 함수를 그대로 를 사용하여 datas를 set해줍니다.

후에 컴포넌트인 Search에 datas와 input, onChange함수를 props로 넘겨줍니다.

 

Search.js

import React, { useState } from "react";
import styled from "styled-components";

const Container = styled.div`
width: 25rem;
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li {
    padding: 1rem 2rem;
    border: 1px solid black;
  }
`;

const StyleInput = styled.input`
  width: 100%;
  height: 3rem;
  padding: 0;
  margin: 0;
  position: relative;
  box-sizing: border-box;
`;

const DataLists = styled.div`
  ${({ visiable }) => {
      return {
          display: visiable === false && "none"
      }
  }}
  width: 100%;
  height: 17rem;
  overflow-y: scroll;
  position: "absolute";
  top: 0;
`;

const Search = ({ datas, input, onChange }) => {
    const [ visiable, setVisiable ] = useState(false);

  return (
    <Container>
      <StyleInput onClick={() => setVisiable(!visiable)} value={input} onChange={onChange} />
      <DataLists visiable={visiable}>
        <ul>
          {datas.map((data, index) => (
            <li key={`${data}_${index}`}>{data}</li>
          ))}
        </ul>
      </DataLists>
    </Container>
  );
};

export default Search;

 코드가 길어보인다면 그것은 스타일드 컴포넌트때문입니다.

아무튼!

visiable을 상태로 관리하여 아이템이 나오는것을 관리해줍니다.

그리고 Input을 relative로 설정하고 DataLists를 absoulte로 설정한 후 top: 0 을 설정해주면 input에 DataLists가 착! 달라붙어 드롭다운효과를 낼 수 있습니다.

이제 DataLists에는 PSearch에 정의되어있던 onChange에의해 datas에는 제가 입력한 input값에 대한 data만 남아있을테니 map을 통해 datas를 통으로 렌더해주면 끝! 입니다!