SEB_FE_44/과제

[coz-shopping] 무한 스크롤

언젠간코딩잘함 2023. 5. 16. 23:46
import React, { useState, useEffect, useRef } from "react";

import Item from "../components/items/Item";
import classes from "./BookmarkPage.module.css";
import Category from "./../components/UI/Category";
import Error from "../components/items/Error";

import img1 from "../assets/img1.png";
import img2 from "../assets/img2.png";
import img3 from "../assets/img3.png";
import img4 from "../assets/img4.png";
import img5 from "../assets/img5.png";

const BookmarkPage = ({ bookmarkState, setBookmarkState }) => {
  const [itemListPage, setItemListPage] = useState([]);
  const [selectedType, setSelectedType] = useState("All");
  const [data, setData] = useState([]);
  const [page, setPage] = useState(1);
  const [load, setLoad] = useState(false);

  const obsRef = useRef(null);
  const preventRef = useRef(true);
  const endRef = useRef(false);

  const categories = [
    { img: img1, name: "전체", type: "All" },
    { img: img2, name: "상품", type: "Product" },
    { img: img3, name: "카테고리", type: "Category" },
    { img: img4, name: "기획전", type: "Exhibition" },
    { img: img5, name: "브랜드", type: "Brand" },
  ];

  const handleIsBookmarked = item => {
    if (bookmarkState) {
      return bookmarkState.some(x => x.id === item.id);
    } else {
      return false;
    }
  };

  const handleSelectCategory = type => {
    setSelectedType(type);
  };

  useEffect(() => {
    setItemListPage(
      bookmarkState
        .filter(item =>
          selectedType === "All" ? true : item.type === selectedType
        )
        .slice(0, 12)
    );
    setPage(1);
  }, [selectedType]);

  useEffect(() => {
    const observer = new IntersectionObserver(obsHandler, {
      threshold: 1.0,
    });
    if (obsRef.current) observer.observe(obsRef.current);
    return () => {
      observer.disconnect();
    };
  }, []);

  useEffect(() => {
    if (page !== 1) getPost();
    console.log(page);
  }, [page]);

  const obsHandler = entries => {
    //옵저버 콜백함수
    const target = entries[0];
    if (target.isIntersecting && preventRef.current) {
      preventRef.current = false; //옵저버 중복 실행 방지
      setPage(prev => prev + 1); //페이지 값 증가
    }
  };

  const timeoutRef = useRef(null);

  const getPost = () => {
    setLoad(true);
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }
    timeoutRef.current = setTimeout(() => {
      const newItems = bookmarkState
        .filter(item =>
          selectedType === "All" ? true : item.type === selectedType
        )
        .slice((page - 1) * 12, page * 12);
      setItemListPage(prev => {
        const uniqueItems = [...new Set([...prev, ...newItems])];
        return uniqueItems;
      });
      preventRef.current = true;
      setLoad(false);
    }, 1000);
  };

  return (
    <div className={classes.itemListPage}>
      <Category
        categories={categories}
        handleSelectCategory={handleSelectCategory}
        selectedType={selectedType}
      />
      <ul className={classes.itemList}>
        {bookmarkState && bookmarkState.length !== 0 ? (
          itemListPage.map(item => {
            return (
              <Item
                key={item.id + "_" + Math.random()}
                item={item}
                isBookmarked={handleIsBookmarked(item)}
                bookmarkState={bookmarkState}
                setBookmarkState={setBookmarkState}
              />
            );
          })
        ) : (
          <Error />
        )}
      </ul>
      <div ref={obsRef}></div>
      {load && <div className={classes.loading}></div>}
    </div>
  );
};

export default BookmarkPage;

 

수정

import React, { useState, useEffect, useRef } from "react";

import Item from "../components/items/Item";
import classes from "./BookmarkPage.module.css";
import Category from "./../components/UI/Category";
import Error from "../components/items/Error";

import img1 from "../assets/img1.png";
import img2 from "../assets/img2.png";
import img3 from "../assets/img3.png";
import img4 from "../assets/img4.png";
import img5 from "../assets/img5.png";

const BookmarkPage = ({ bookmarkState, setBookmarkState }) => {
  const [itemListPage, setItemListPage] = useState([]);
  const [selectedType, setSelectedType] = useState("All");
  const [page, setPage] = useState(1);
  const [load, setLoad] = useState(false);

  const obsRef = useRef(null);
  const preventRef = useRef(true);
  const endRef = useRef(false);

  const categories = [
    { img: img1, name: "전체", type: "All" },
    { img: img2, name: "상품", type: "Product" },
    { img: img3, name: "카테고리", type: "Category" },
    { img: img4, name: "기획전", type: "Exhibition" },
    { img: img5, name: "브랜드", type: "Brand" },
  ];

  const handleIsBookmarked = item => {
    if (bookmarkState) {
      return bookmarkState.some(x => x.id === item.id);
    } else {
      return false;
    }
  };

  const handleSelectCategory = type => {
    setSelectedType(type);
  };

  const updateData = (start, end) => {
    setItemListPage(
      bookmarkState
        .filter(item =>
          selectedType === "All" ? true : item.type === selectedType
        )
        .slice(start, end)
    );
  };

  useEffect(() => {
    const observer = new IntersectionObserver(obsHandler, {
      threshold: 1.0,
    });
    if (obsRef.current) observer.observe(obsRef.current);
    return () => {
      observer.disconnect();
    };
  }, []);

  const obsHandler = entries => {
    const target = entries[0];
    if (target.isIntersecting && preventRef.current) {
      preventRef.current = false; //옵저버 중복 실행 방지
      setPage(prev => prev + 1); //페이지 값 증가
    }
  };

  useEffect(() => {
    updateData(0, page * 12);
  }, [bookmarkState]);

  useEffect(() => {
    updateData(0, 12);
    setPage(1);
  }, [selectedType]);

  useEffect(() => {
    if (page !== 1) getPost();
  }, [page]);

  let timer = null;
  const getPost = () => {
    setLoad(true);
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      setItemListPage(prev => [
        ...prev,
        ...bookmarkState
          .filter(item =>
            selectedType === "All" ? true : item.type === selectedType
          )
          .slice((page - 1) * 12, page * 12),
      ]);
      preventRef.current = true;
      setLoad(false);
    }, 500);
  };

  return (
    <div className={classes.itemListPage}>
      <Category
        categories={categories}
        handleSelectCategory={handleSelectCategory}
        selectedType={selectedType}
      />
      <ul className={classes.itemList}>
        {bookmarkState && bookmarkState.length !== 0 ? (
          itemListPage.map(item => {
            return (
              <Item
                key={item.id + "_" + Math.random()}
                item={item}
                isBookmarked={handleIsBookmarked(item)}
                bookmarkState={bookmarkState}
                setBookmarkState={setBookmarkState}
              />
            );
          })
        ) : (
          <Error />
        )}
      </ul>
      <div ref={obsRef}></div>
      {load && <div className={classes.loading}></div>}
    </div>
  );
};

export default BookmarkPage;