ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 무한스크롤 구현하기
    카테고리 없음 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컴포넌트를 따로 만들어서 작업하시던 것과 비슷하다고 생각했다. 데이터를 어떻게 관리하느냐가 어려운 것 같다. 

     

     

Designed by Tistory.