카테고리 없음

무한스크롤 구현하기

jann2 2022. 1. 12. 23:24

지난번에 공부했던 react-infinite-scroll-component를

우리 프로젝트의 검색페이지에 적용시켜 보았다.

 

import React from "react";
import styled from "styled-components";
import InfiniteScroll from "react-infinite-scroll-component";
import { useEffect, useState, useRef } from "react";
import Track from "../../components/mypage/Track";
import { useLocation } from "react-router-dom";
import { apis } from "../../shared/api";
import Header from "../../components/category/Header";
import { Container } from "../../elements/index";
import search, {
  actionCreators as searchActions,
} from "../../redux/modules/search";
import { useDispatch, useSelector } from "react-redux";

import { RiArrowLeftSLine } from "react-icons/ri";
import { HiOutlineSearch } from "react-icons/hi";

const KeywordSearch = (props) => {
  const dispatch = useDispatch();
  const trackWrapRef = useRef(null);
  const location = useLocation();
  const keyword = location.state.value;
  const search_list = useSelector((state) => state.search.search_list);
  console.log("search_list", search_list);

  const [items, setItems] = useState([]);
  const [hasMore, setHasMore] = useState(true);
  const [page, setPage] = useState(2);

  useEffect(() => {
    //데이터 가져오기
    const getsearchList = async (keyword, pages, track) => {
      const res = await apis.search(
        (keyword = location.state.value),
        (pages = 1),
        (track = 12)
      );

      const data = await res.data.tracks; //리스폰스를 const data에 저장
      setItems(data); //items는 현재 빈배열. 여기에 처음 12개 데이터를 set해주기
    };
    getsearchList();
  }, []);

  const fetchSearch = async (keyword, pages, track) => {
    console.log("page", page);
    const res = await apis.search(
      (keyword = location.state.value),
      (pages = `${page}`),
      (track = 12)
    );

    const data = await res.data.tracks;
    return data;
  };

  const fetchData = async () => {
    const searchFormServer = await fetchSearch();
    setItems([...items, ...searchFormServer]);

    if (searchFormServer.length === 0 || searchFormServer.length < 12) {
      setHasMore(false);
    }
    setPage(page + 1);
  };
  console.log("items", items);

  const inputRef = React.useRef();

  const handleSearch = () => {
    const value = inputRef.current.value;
    if (value.length < 2) {
      window.alert("검색어를 두 글자 이상 입력해주세요OAO!");
    }
    // else {
    //   dispatch(searchActions.getSearchDB(value));
    // }
  };

  useEffect(() => {
    handleSearch();
  }, []);

  const onClick = () => {
    handleSearch();
  };

  const onKeyPress = (event) => {
    if (event.key === "Enter") {
      handleSearch();
    }
  };

  return (
    <div>
      {items && items.length > 0 ? (
        <>
          <InfiniteScroll
            dataLength={items.length}
            next={fetchData}
            hasMore={hasMore}
            loader={<h4>Loading...</h4>}
            endMessage={
              <p style={{ textAlign: "center" }}>
                <b>Yay! You have seen it all</b>
              </p>
            }
          >
            <Header topMenu />
            <Container>
              <Flex>
                <Flex
                  onClick={() => {
                    props.history.push("/searchKeyword");
                  }}
                >
                  <RiArrowLeftSLine
                    size="30"
                    cursor="pointer"
                  ></RiArrowLeftSLine>
                </Flex>

                <Multiline
                  ref={inputRef}
                  onKeyPress={onKeyPress}
                  placeholder="검색어를 두글자 이상 입력해주세요."
                  type="text"
                  defaultValue={keyword}
                ></Multiline>
                <HiOutlineSearch
                  size="30"
                  cursor="pointer"
                  onClick={onClick}
                ></HiOutlineSearch>
              </Flex>
            </Container>
            <Grid>
              <TrackGrid ref={trackWrapRef}>
                {items.map((l) => {
                  return (
                    <TrackDiv key={l.trackId}>
                      <Track {...l} trackWrapRef={trackWrapRef.current} />
                    </TrackDiv>
                  );
                })}
              </TrackGrid>
            </Grid>
          </InfiniteScroll>
        </>
      ) : (
        <>
          <Header topMenu />
          <Container>
            <Flex>
              <Flex
                onClick={() => {
                  props.history.push("/searchKeyword");
                }}
              >
                <RiArrowLeftSLine size="30" cursor="pointer"></RiArrowLeftSLine>
              </Flex>
              <Multiline
                ref={inputRef}
                onKeyPress={onKeyPress}
                placeholder="검색어를 두글자 이상 입력해주세요."
                type="text"
                defaultValue={keyword}
              ></Multiline>
              <HiOutlineSearch
                size="30"
                cursor="pointer"
                onClick={onClick}
              ></HiOutlineSearch>
            </Flex>
            <OAODiv>
              <OAOText>검색결과가 없습니다</OAOText>
              <OAOText>다시 한번 검색해주세요!</OAOText>
              <OAO></OAO>
            </OAODiv>
          </Container>
        </>
      )}
    </div>
  );
};

const Flex = styled.div`
  display: flex;
  align-items: center;
  vertical-align: center;
`;

const Multiline = styled.input`
  border: none;
  background: none;
  border-bottom: solid 3px #ddd;
  padding: 12px 4px;
  width: 100%;
  color: #fff;

  :focus {
    border: none;
    background: none;
    border-bottom: solid 3px var(--point-color);
  }
`;

const Grid = styled.div`
  padding-left: 10px;
  /* @media screen and (max-width: 375px) {
    padding-left: 0px;
  } */
`;

const TrackGrid = styled.div`
  max-width: 425px;
  width: 100%;
  margin: auto;
  display: flex;
  flex-wrap: wrap;
`;

const TrackDiv = styled.div`
  margin: 0px 10px;
  @media screen and (max-width: 375px) {
    margin: 0 5px;
  }
  @media screen and (max-width: 320px) {
    margin: 0 1px;
  }
`;

const OAODiv = styled.div`
  position: relative;
  margin-top: 120px;
`;

const OAOText = styled.p`
  font-size: 14px;
  text-align: center;
  margin-bottom: 12px;
`;

const OAO = styled.div`
  width: 156px;
  height: 156px;
  margin: 40px auto 0px auto;

  background-image: url("/assets/images/OAO.png");
  background-repeat: no-repeat;
  background-size: cover;
`;
export default KeywordSearch;

데이터는 잘 받아와지고 무한스크롤도 잘 되고있는데

문제는 검색을 한번만 하는 것은 아니라는 것...

 

의문

1. 검색을 다시 하게되면 겹치는 데이터가 발생하진 않을까?

=> 리덕스로 데이터를 관리해보기로 했다.(페이징 처리도 리덕스에서 해보기로 함)

 

2. 현재 상세페이지를 들어갔다 나오면 reload가 되고 있는데 reload가 되면서 1페이지로 가게되는 문제점

(사용자가 보던 페이지가 사라지고 스크롤이 제일 상단으로 가게된다.)

=> 상세페이지 기능을 담당 해주신 용성님이 reload를 없애주기로 했다.

 

회고

무한스크롤 자체는 생각보다 어렵지 않았다. 예전 강의에서 튜터님이 infinitescoll컴포넌트를 따로 만들어서 작업하시던 것과 비슷하다고 생각했다. 데이터를 어떻게 관리하느냐가 어려운 것 같다.