ToyProject - 검색 기능 만들기

응애 나 프론트애긔👶·2022년 7월 28일
0
post-thumbnail

검색 기능 만들기


해당 프로젝트의 요구 내용은 다음과 같다.

  • API를 가져와서 사용 할 수 있는가 ?
  • 북마크(즐겨찾기) 기능을 구현 할 수 있는가 ?
  • input의 value를 API에서 검색 할 수 있는가 ?
  • 검색한 내용을 저장할 수 있는가 ? (최근 검색어)
  • 무한 스크롤을 구현 할 수 있는가 ?

위의 내용을 모두 만족하는 검색 기능을 만드는 토이 프로젝트이다.

NYT Search API를 사용합니다유






NYT에서 제공해주는 API가 여러 개 있다.




위의 여러 API 중 우리는 검색을 이용한 API 이기 때문에 Article Search API를 사용한다 !

API 사용은 간단한데 회원가입하고 KEY를 받아온 다음 API URL에 나의 KEY를 URL을 넣어서 사용하면 끝 !

자바스크립트에서 fetch를 사용하여 불러 온 후 API의 data를 사용하여 구현하는 걸로 접근했다.

input의 value를 검색합니다유



input의 value를 얻는 기능인데 간단히 말해 검색 기능이다.

접근 방식은 다음과 같다.

  1. input을 만들어 keyup 이벤트로 동작하도록 만든다.
  2. keyup이 동작하면 input의 value를 가져온다.
  3. input의 value를 확인하고 해당 value를 가진 API Data를 찾는다.

해당 접근 방식은 추가적인 에러 없이 잘 구현이 되었다.

이후에 0.5 이후에 input에 특정 이벤트가 없어도 자동으로 submit 되도록 구현하는 것과 최근 검색어를 구현하는 것이다.

이는 setTimeout을 이용하여 구현을 했고 최근 검색어는 하나의 빈 배열을 만들어 value를 넣어주는 형식으로 구현했다.


다음은 북마크 입니다유



요즘 웹/앱에 없어서는 안되는 기능 중 하나인 북마크(즐겨찾기) 기능이다.

접근 방식은 다음과 같다.

  1. News에 BookMarkbutton을 생성
  2. See BookMark 버튼 생성 (북마크 News만 보기 위한 토글 버튼)
  3. 해당 버튼을 클릭 시 BookMarkList라는 빈 배열에 넣도록 함
  4. See BookMark라는 버튼을 클릭하게 된다면 북마크 된 News를 렌더링
  5. BookMarkbutton도 토글 형태로 만들고 UnBookMark를 되었을 때 클릭하면 BookMarkList 배열에서 해당 News를 제거

해당 접근 방식은 추가적인 에러 없이 잘 구현이 되었다.


마지막으로 무한 스크롤이여유



무한 스크롤은 웹 사이트에서 꽤나 많이 볼 수 있다.

사실 말이 무한 스크롤이지 특정 HTML Element이 ViewPort의 특정 부분을 지나면 다음 HTML Element를 보여주는 기능이다.

한번도 구현해 본 적이 없어서 구글링을 하였는데 두 가지 방법이 나왔다.


1. scroll 이벤트를 활용하여 스크롤에 이벤트를 넣어 구현하는 방법
2. Intersection Observer를 사용하여 구현하는 방법


구글링으로 두 구현 방법을 비교해봤는데

scroll 이벤트를 사용하게 되면 스크롤을 내리는 순간 모든 이벤트들이 발생하고 그로 인해 reflow가 발생하게 된다.

이러한 단점 때문에 이번엔 Intersection Observer API를 사용 해볼까 한다.

Intersection Observer

const io = new IntersectionObserver(callback, option);
io.observe(처음 감지할 Element);

간단하게 위와 같이 구성되어 있다.

먼저 Intersection Observer 안을 살펴보자.

먼저 callback 함수를 살펴보면

관찰할 대상이 등록되거나 가시성에 변화가 생기면 관찰자는 콜백을 실행하게 된다.

이때 콜백은 entries와 observer이라는 인자를 받게 된다.

먼저 entries는 아래와 같은 속성들이 있다.

  • boundingClientRect: 관찰 대상의 사각형 정보

  • intersectionRect: 관찰 대상의 교차한 영역 정보

  • intersectionRatio: 관찰 대상의 교차한 영역 백분율
    (Number)

  • isIntersecting: 관찰 대상의 교차 상태(Boolean)

  • rootBounds: 지정한 루트 요소의 사각형 정보

  • target: 관찰 대상 요소

  • time: 변경이 발생한 시간 정보


위의 속성 중 마음에 드는 것을 골라 원하는 ViewPort에서 Element가 어떤 교차를 할 때 반응하도록 구현하면 된다.

그 다음 인자인 observer는 콜백이 실행되는 해당 인스턴스를 참조한다.

마지막으로 callback과 같이 받는 option이 있는데 option에도 여러 프로퍼티들이 존재한다.


  • root: 타겟의 가시성을 검사하기 위해 뷰포트 대신 사용할 요소 객체를 지정한다.

  • rootMargin: margin을 이용해 root 범위를 확장하거나 축소할 수 있다.

  • threshold: 옵저버가 실행되기 위해 타겟의 가시성이 얼마나 필요한지 백분율로 표시해준다.


위와 같이 설정을 하면 되고 다음은 메소드들을 살펴보자


  • observe: 대상 요소의 관찰을 시작한다.

  • unobserve: 대상 요소의 관찰을 중지한다. 중지할 때는 하나의 대상 요소를 인수로 정해야한다.
    단 IntersectionObserver 가 관찰하고 있지 않은 대상 요소가 인수로 지정되면 아무런 동작도 안한다.

  • disconnect: IntersectionObserver 가 관찰하는 모든 요소의 관찰을 중지한다.



구현하면서 어려웠던 점



keyup 이벤트 문제 !

먼저 처음으로 막혔던 부분은 input value를 0.5초에 자동 검색을 해야하는데 keyup 이벤트를 사용하여 submit을 구현 했었다.

아 뿔 싸.

그런데 채팅을 치게 될 때 마다 최근 검색어가 쫘르르르륵 올라가는 것이다.

이는 keyup 이벤트를 사용해서 일어나는 현상인데 이를 해결하기 위해 setTimeout을 다시 한번 더 사용했다.

구글링에서 javascript keyup delay 라고 검색하니 잘 나와있었다.

const delay = (() => {
      let timer = 0;
      return function (callback, ms) {
        clearTimeout(timer);
        timer = setTimeout(callback, ms);
      };
    })();



API는 10개 ... Too Many Requests

API를 불러 왔는데 10개만 준다 ...

아니 News를 10개만 주는데 어떻게 무한 스크롤을 구현하라는 것인가.

그렇게 NYT API 공식 문서를 읽어보니 관련 글을 찾을 수 있었다.

바로 url에 page를 사용해 결과 값을 10개씩만 가져온다는 것이였는데 parameter를 수시로 변경하여야 한다는 것이다.

이걸로 무한 스크롤을 구현하려고 고민하는데 시간을 많이 소비한 것 같다.

미친척 fetch를 중첩으로 만들어 페이지를 모을까 결정하던 찰라 스크롤이 맨 아래로 내려갈 때 새로운 API를 호출하기로 했다.

그런데 문제점은 API가 여러번 호출 되다보니 Too Many Requests 에러가 나왔다.

혹시나 너무나 빠른 스크롤 다운으로 인해 이전 API호출과 현재 API호출이 겹치지 않는지 확인했는데 겹치는 문제 없이 잘 호출 되었다.

그런데 이상하게도 스크롤을 천천히 내려도 같은 결과가 나온다 ...

+ 0809 추가

대표적인 인스타그램과 트위터를 찾아본 결과 스크롤이 바닥에 닿으면 API를 계속해서 호출해낸다.

무한 스크롤 구현이 처음이라 이러한 형태로 API를 가져오는 것이 현명한지 아닌지 의심이 들었다.

기존에 내가 API를 다룰 땐 한 API에서 Data를 사용하는 것인데 스크롤 마다 새로운 API를 가져오니 당황했고 이런 방식을 부정했던거 같다. (어리석은...)

그렇게 호출되는 API에만 사용하려다 보니 API 호출을 난발하게 되었고 그렇게 너무 많은 양의 호출이 있다보니 에러가 난 것이였다.

현재는 스크롤이 바닥에 닿을 때 한 번 새로운 API를 가져오도록 수정했다.



망할 북마크 ...

가장 어려웠고 구현에 실패한 북마크이다.

북마크가 뭐가 어렵냐고 생각이 드실 수 있겠지만 꽤나 애먹었다. 그리고 실패했다...

접근 방법은 나쁘지 않았다. 북마크를 클릭하면 빈 배열 안에 해당 News를 넣어 놨다가 북마크를 보고 싶을 때

배열 안에 있는 북마크를 꺼내 오는 형식이였다.

근데 꺼내오는 과정에서 현재 호출 되는 10개의 API만 북마크 기능이 활성화 된다...

문제 발생 🚨
만약 현재 API의 page가 1이라면 이전 page0의 게시글을 북마크 할 수 없다.

이유는 불러오는 API는 10개로 한정되어 있어 무한스크롤로
현재 page110 ~ 19이라는 data를 불러 온 상태라고 가정하면

지금 API는 10 ~ 19data만 있기 때문에 page0에 있는 0 ~ 9 라는 data
북마크를 눌러 bookMarkList 배열에 넣어도 불러올 수 없다는 소리다.

이전 API는 사라지고 새로운 API가 나왔기 때문에 발생한 문제이다.

그렇게 다른 시도를 해봤는데

  1. 요소들을 clone(복제)해서 저장 (실패)

  2. API를 불러오는 족족 빈 배열에 저장 (말 같지도 않은...)

그래서 인스타그램이랑 트위터 (대표적인 무한 스크롤 웹 2개)는 어떻게 사용되는지 확인 했는데
두 사이트 모두 북마크 된 게시글을 다시 서버로 전송을 한다.

아마 사용자의 북마크 리스트에 더하기 위한 것 같은데... 쓸만한 힌트는 찾지 못했다.

아쉬운 마음으로 구현에 실패하고 React를 공부하는 중이다.

+ 0809 추가

강사님이 주신 코드를 보며 뭐가 문제인지 알아보았다.

지금 내 코드의 문제점은 Clip하는 Element를 API에서 ClipList에 넣어 사용을 하니 당연히 API가 새롭게 들어오면 이전 API Data에서 ClipList를 가져올 수 없다.

강사님의 코드를 보니 검색한 News들을 렌더링 할 때 Clip Btn에 이벤트 안에 해당 Element를 ClipList에 바로 넣으셨다.

이와 같은 방법으로 문제를 해결했다.

어리석게도 이제껏 API의 Data에만 의존하다보니 어떠한 작업을 할 때마다 API를 불러와서 Data를 사용하는 바보같은 짓을 했다.

API는 단 한 번만 가져오고 그 가져온 Data를 요리하는 법을 깨달았다.



마지막으로... 포기 하지 말아요...


개인적인 생각으론 해당 과제가 수업의 내용보다 훠어어어어어얼씬 어렵게 나왔다.

비유하자면 세 발 자전거 타는 법을 알려주고 레이싱 카를 운전 하라는 느낌이였다.

일단 스터디원과 조원 분들이 감을 잡을 수 있도록 최소한의 접근 방법은 공유해드렸다. (코드를 알려줄 수는 없고 😓)

그럼에도 불구하고 API를 가져오시는 것도 처음이고 DOM을 사용하여 만드는 것도 처음이시니 조금 걱정스럽기도 하다.

최대한 이끌어가며 다들 수료라는 첫 번째 봉우리에서 만세를 외치고 싶기 때문에 최대한 설명하고 이해시켜 드리고 싶다.

+ 0809

리팩토링 완료.

  • 반복되는 코드 함수를 사용하여 코드를 재사용함

  • 기존 문제점 해결 (Too many request 에러, 북마크)


0개의 댓글