From e361c9c64efa03999fa079b750da4d18add0a37d Mon Sep 17 00:00:00 2001 From: novice1993 Date: Fri, 14 Jul 2023 03:55:28 +0900 Subject: [PATCH 1/8] =?UTF-8?q?=EB=AC=B4=ED=95=9C=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=EC=9D=BC=EB=B6=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 상품 리스트 무한 스크롤 구현함 -> 스크롤 아래로 내리면 서버에서 신규 데이터 받아옴. 받아온 신규 데이터와 기존 데이터 비교 후 중복값 제거 후 로컬 스토리지에 저장. 기존에 받아온 데이터도 날아가지 않고 계속해서 조회 가능하도록 구현 (상품리스트 외 다른 페이지로 url 이동 시 로컬 스토리지에 저장한 상품 리스트 초기화) - 북마크 리스트 무한 스크롤 구현 중, 배열 데이터의 index 활용하여 위/아래로 스크롤 이동 시 상품 렌더링 되도록 구현 예정 --- coz-shopping/src/Component/ItemFilter.js | 12 +---- coz-shopping/src/Component/Modal.js | 2 +- coz-shopping/src/Page/BookmarkListPage.js | 41 ++++++++++++++++-- coz-shopping/src/Page/ItemListPage.js | 53 ++++++++++++++++++++++- coz-shopping/src/Page/MainPage.js | 2 +- 5 files changed, 92 insertions(+), 18 deletions(-) diff --git a/coz-shopping/src/Component/ItemFilter.js b/coz-shopping/src/Component/ItemFilter.js index 2b8ecf799..86dc7d37c 100644 --- a/coz-shopping/src/Component/ItemFilter.js +++ b/coz-shopping/src/Component/ItemFilter.js @@ -33,21 +33,11 @@ const Text = styled.div` text-align: center; ` -function ItemFilter ({ setItems, all_Items, bookmarkPage_Items }) { - - const [filter, setFilter] = useState(''); // 필터링 조건 +function ItemFilter ({ filter, setFilter, setItems, all_Items, bookmarkPage_Items }) { useEffect(() => { - - // 1. 상품 리스트에서 필터링 할 때 - if(bookmarkPage_Items === undefined){ (filter === 'all') ? setItems(all_Items) : setItems(all_Items.filter((item) => item.type === filter)) - // 2. 북마크 리스트에서 필터링 할 때 - } else { - (filter === 'all') ? setItems(all_Items) - : setItems(bookmarkPage_Items.filter((item) => item.type === filter)) - } }, [filter]) diff --git a/coz-shopping/src/Component/Modal.js b/coz-shopping/src/Component/Modal.js index cca2afa69..e4d123402 100644 --- a/coz-shopping/src/Component/Modal.js +++ b/coz-shopping/src/Component/Modal.js @@ -1,7 +1,7 @@ import { styled } from "styled-components"; const Background = styled.div` - position: absolute; + position: fixed; z-index: 99; top: 0; left: 0; diff --git a/coz-shopping/src/Page/BookmarkListPage.js b/coz-shopping/src/Page/BookmarkListPage.js index b2e5e7c75..e44d80fb0 100644 --- a/coz-shopping/src/Page/BookmarkListPage.js +++ b/coz-shopping/src/Page/BookmarkListPage.js @@ -46,13 +46,48 @@ const ItemBox = styled.div` function BookmarkListPage ({ bookmark_List, setBookmark_List }) { - const all_bookmark = JSON.parse(localStorage.getItem('bookmark')); + const all_bookmark = JSON.parse(localStorage.getItem('bookmark')); + const [filter, setFilter] = useState(''); // 필터링 조건 const [bookmarkPage_Items, setBookmarkPage] = useState([]); // 북마크 페이지 화면에 노출되는 데이터 + const [index, setIndex] = useState(4); // 화면엪 표시될 상품 index 관련 상태 + + // 🔴 배열의 index 값 이용해서 무한 스크롤 구현 중 -> 아래/위로 자유롭게 이동 가능하도록 구현 (스크롤 윗 부분도 알아볼 것) + // 상품 리스트도 동일한 로직 적용해서 수정 useEffect(() => { - setBookmarkPage(all_bookmark) + const data = all_bookmark.filter((item, idx) => { + return (idx 레퍼런스 참고해서 구현함 => 이를 활용해서 데이터 올바르게 처리할 로직 구현해야 함 (https://abangpa1ace.tistory.com/118) 참고 + const handleScroll =() => { + + const { scrollHeight, scrollTop, clientHeight } = document.documentElement; + + if (scrollTop + clientHeight >= scrollHeight) { + if(index < all_bookmark.length){ + setIndex(index+4);} + + window.scrollTo(0, scrollTop-1) + } + } + + useEffect(() => { + window.addEventListener('scroll', handleScroll); + return () => window.removeEventListener('scroll', handleScroll); + }, [handleScroll]) + + useEffect(() => { + const data = all_bookmark.filter((item, idx) => { + return (idx>index-5 && idx @@ -60,7 +95,7 @@ function BookmarkListPage ({ bookmark_List, setBookmark_List }) {
- + {bookmarkPage_Items.map((item) => { return ( { @@ -67,7 +68,55 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { request(); }, []) - + + + // 무한 스크롤 -> 레퍼런스 참고해서 구현함 => 이를 활용해서 데이터 올바르게 처리할 로직 구현해야 함 (https://abangpa1ace.tistory.com/118) 참고 + const handleScroll =() => { + + const { scrollHeight, scrollTop, clientHeight } = document.documentElement; + + if (scrollTop + clientHeight >= scrollHeight) { + + const request = async () => { + try { + const res = await fetch('http://cozshopping.codestates-seb.link/api/v1/products?count=8') + const data = await res.json(); + + const previousItem = JSON.parse(localStorage.getItem('all_Items')); // 1) 기존에 로컬에 저장한 상품 데이터 + + console.log(previousItem); + + const newItem = data.filter((item) => { // 2) 기존 데이터 - 새로 불러온 데이터 : 중복 검사 + let result = 0; + for(let i=0; i 로컬에 저장 + localStorage.setItem('all_Items', JSON.stringify(newItemList)); + + (filter === '' || filter === 'all') ? setItems(newItemList) // 4) 현재 필터 고려 -> 렌더링 될 상태로 설정 + : setItems(newItemList.filter((item) => item.type === filter)) + + } catch (error) { + console.log('Response error', error); + } + } + + request(); + + window.scrollTo(0, scrollTop-1) + } + } + + useEffect(() => { + window.addEventListener('scroll', handleScroll); + return () => window.removeEventListener('scroll', handleScroll); + }, [handleScroll]) + + return ( @@ -75,7 +124,7 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) {
- + {items.map((item) => { return diff --git a/coz-shopping/src/Page/MainPage.js b/coz-shopping/src/Page/MainPage.js index 454a533d0..400d665fd 100644 --- a/coz-shopping/src/Page/MainPage.js +++ b/coz-shopping/src/Page/MainPage.js @@ -31,7 +31,7 @@ function MainPage ({ bookmark_List, setBookmark_List }) { console.log('Response error', error); } } - + request(); }, []) From 3acf3aa3534068196fbb307431703200a48f6a15 Mon Sep 17 00:00:00 2001 From: novice1993 Date: Fri, 14 Jul 2023 17:30:38 +0900 Subject: [PATCH 2/8] =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 북마크 등록 및 갱신 관련 오류 수정 - 불필요한 상태 변수 삭제 및 코드 정리하여 가독성 증진 --- coz-shopping/src/App.js | 2 +- coz-shopping/src/Component/BookmarkItem.js | 41 ++++------ coz-shopping/src/Component/Item.js | 45 +++++------ coz-shopping/src/Component/ItemFilter.js | 14 +++- .../Component/MainComponent/BookmarkList.js | 8 ++ .../src/Component/MainComponent/ItemList.js | 2 +- coz-shopping/src/Page/BookmarkListPage.js | 81 +++++++++++-------- coz-shopping/src/Page/MainPage.js | 10 +-- 8 files changed, 106 insertions(+), 97 deletions(-) diff --git a/coz-shopping/src/App.js b/coz-shopping/src/App.js index c1fbd142e..8811e8766 100644 --- a/coz-shopping/src/App.js +++ b/coz-shopping/src/App.js @@ -9,7 +9,7 @@ import { BrowserRouter, Routes, Route } from 'react-router-dom'; function App() { const bookmarkData = JSON.parse(localStorage.getItem('bookmark')); - const [bookmark_List, setBookmark_List] = useState(bookmarkData); // 북마크 리스트 + const [bookmark_List, setBookmark_List] = useState( (bookmarkData !== null) ? bookmarkData : [] ); return ( diff --git a/coz-shopping/src/Component/BookmarkItem.js b/coz-shopping/src/Component/BookmarkItem.js index 059d14bfc..30f6b6d63 100644 --- a/coz-shopping/src/Component/BookmarkItem.js +++ b/coz-shopping/src/Component/BookmarkItem.js @@ -57,40 +57,29 @@ const Followers = styled.div` text-align: right; ` -function BookmarkItem ({ bookmarkItem, bookmark_List, setBookmark_List, bookmarkPage_Items, setBookmarkPage}) { +function BookmarkItem ({ + bookmarkItem, // 렌더링 할 개별 아이템 + bookmark_List, setBookmark_List // 북마크 전역상태, 상태관리 함수 + }) { - const [bookmark, setBookmark] = useState(true); // 아이템 북마크 여부 - const [modal, setModal] = useState(false); // 모달창 on/off + const [bookmark, setBookmark] = useState(true); + const [modal, setModal] = useState(false); - - const bookmarkButtonClick = () => { - setBookmark(!bookmark); - } - - const modalButtonClick = () => { - setModal(!modal); - } + const bookmarkButtonClick = () => { setBookmark(!bookmark); } + const modalButtonClick = () => { setModal(!modal); } + // 2. 북마크 취소 -> 1) 로컬 스토리지 데이터 갱신 2) 전역 상태 변경 ( 북마크 리스트에서 해당 아이템 삭제 ) useEffect(() => { + if(!bookmark){ - setBookmark_List(bookmark_List.filter((item) => { - return item.id !== bookmarkItem.id - })) - - if(bookmarkPage_Items !== undefined ){ // 북마크 리스트 페이지에서 화면에 표시되는 데이터 갱신 - setBookmarkPage(bookmarkPage_Items.filter((item) => { - return item.id !== bookmarkItem.id - })) - } - } - }, [bookmark]) // 북마크에 변화 (버튼 클릭) -> 화면 렌더링에 관여하는 데이터를 갱신 (해당 화면에서는 갱신 ok) - useEffect(() => { - const bookmarkData = JSON.stringify(bookmark_List) // 로컬 스토리지에 저장 - localStorage.setItem('bookmark', bookmarkData); + const bookmarData = (bookmark_List.filter((item) => item.id !== bookmarkItem.id)) - }, [bookmark_List]) + localStorage.setItem('bookmark', JSON.stringify(bookmarData)); + setBookmark_List(bookmarData) + + }}, [bookmark]) return ( <> diff --git a/coz-shopping/src/Component/Item.js b/coz-shopping/src/Component/Item.js index d7c853e32..0861771b9 100644 --- a/coz-shopping/src/Component/Item.js +++ b/coz-shopping/src/Component/Item.js @@ -57,39 +57,36 @@ const Followers = styled.div` function Item ({ item, bookmark_List, setBookmark_List }) { - const [bookmark, setBookmark] = useState(false); // 아이템 북마크 여부 - const [modal, setModal] = useState(false); // 모달창 on/off - const check = bookmark_List.find((bookmakrItem) => bookmakrItem.id === item.id); // 기존 북마크에 포함된 정보인지 체크 + const [bookmark, setBookmark] = useState(false); + const [modal, setModal] = useState(false); + const check = bookmark_List.find((bookmakrItem) => bookmakrItem.id === item.id); // 이전에 북마크 등록된 아이템인지 체크 - const bookmarkButtonClick = () => { - setBookmark(!bookmark); - } - - const modalButtonClick = () => { - setModal(true); - } + const bookmarkButtonClick = () => { setBookmark(!bookmark); } + const modalButtonClick = () => { setModal(true); } - useEffect(() => { // 1. 서버에서 item 불러오거나, 필터링 했을 때 -> 이전에 북마크 기처리 했을 시 별표에 색상 - (check !== undefined) && setBookmark(true); - }, [item]) + useEffect(() => { // item 정보 다시 불러왔을 때 -> 이전에 북마크 등록한 item일 경우 -> true값 부여 + (check !== undefined) && setBookmark(true)}, [item]) - useEffect(() => { // bookmark true일 때 -> 신규로 체크한 것만 북마크에 추가 (1번 useEffect로 인한 외부효과 방지) + useEffect(() => { // 신규 등록 혹은 해제 -> 1) 로컬 데이터 갱신 2) 북마크 전역상태 갱신 - (bookmark && check === undefined) && setBookmark_List([...bookmark_List, item]); - (!bookmark) && (setBookmark_List(bookmark_List.filter((bookmarkItem) => {return bookmarkItem.id !== item.id}))); - }, [bookmark]) + if(bookmark === true && check === undefined){ + const newData = [...bookmark_List, item] + + localStorage.setItem('bookmark', JSON.stringify(newData)); + setBookmark_List(newData); - useEffect(() => { // 북마크 체크 해제 시 -> 로컬 스토리지에 기록 저장 - - (check === undefined) && setBookmark(false) + } else if (bookmark === false) { + + const newData = bookmark_List.filter((bookmarkItem) => {return bookmarkItem.id !== item.id}); + + localStorage.setItem('bookmark', JSON.stringify(newData)); + setBookmark_List(newData) + } + }, [bookmark]) - const bookmarData = JSON.stringify(bookmark_List) - localStorage.setItem('bookmark', bookmarData); - - }, [bookmark_List]) return ( <> diff --git a/coz-shopping/src/Component/ItemFilter.js b/coz-shopping/src/Component/ItemFilter.js index 86dc7d37c..a6e54a1b9 100644 --- a/coz-shopping/src/Component/ItemFilter.js +++ b/coz-shopping/src/Component/ItemFilter.js @@ -33,11 +33,17 @@ const Text = styled.div` text-align: center; ` -function ItemFilter ({ filter, setFilter, setItems, all_Items, bookmarkPage_Items }) { +function ItemFilter ({ + filter, setFilter, // 필터 관련 상태 + setItems, // 북마크 전역 상태관리 함수 + all_Items // 로컬 스토리지 데이터 +}) { - useEffect(() => { - (filter === 'all') ? setItems(all_Items) - : setItems(all_Items.filter((item) => item.type === filter)) + useEffect(() => { // 필터를 변경했을 때 + + (filter === 'all') ? setItems(all_Items) // if) 전체 데이터 : 북마크 전역 상태를 로컬 스토리지 데이터로 변경 + : setItems(all_Items.filter((item) => item.type === filter)) // if-2) 특정 조건 : 로컬 스토리지 데이터를 필터링 해서 전역 상태로 설정 + }, [filter]) diff --git a/coz-shopping/src/Component/MainComponent/BookmarkList.js b/coz-shopping/src/Component/MainComponent/BookmarkList.js index 7a8ba25b1..31918dd6a 100644 --- a/coz-shopping/src/Component/MainComponent/BookmarkList.js +++ b/coz-shopping/src/Component/MainComponent/BookmarkList.js @@ -1,5 +1,6 @@ import { styled } from "styled-components"; import BookmarkItem from "../BookmarkItem"; +import { useEffect } from "react"; const Container = styled.div` height: 100%; @@ -47,6 +48,13 @@ const Emptybox = styled.div` function BookmarkList ({ bookmark_List, setBookmark_List }) { + + // MainPage로 이동 시 -> 로컬 스토리지에 있는 전체 북마크 리스트를 화면에 불러옴 + useEffect(() => { + const all_bookmark = JSON.parse(localStorage.getItem('bookmark')); + setBookmark_List(all_bookmark); + }, []) + return ( 북마크 리스트 diff --git a/coz-shopping/src/Component/MainComponent/ItemList.js b/coz-shopping/src/Component/MainComponent/ItemList.js index 36efca4a0..a3fc2e96f 100644 --- a/coz-shopping/src/Component/MainComponent/ItemList.js +++ b/coz-shopping/src/Component/MainComponent/ItemList.js @@ -28,7 +28,7 @@ const ItemBox = styled.div` margin-top: 10px; ` -function ItemList ({ items, bookmark_List, setBookmark_List }) { +function ItemList ({ items, bookmark_List, setBookmark_List }) { // 1) MainPage가 마운트 될 때 서버에서 받아온 데이터 2) 북마크 관련 전역 상태 return ( 상품 리스트 diff --git a/coz-shopping/src/Page/BookmarkListPage.js b/coz-shopping/src/Page/BookmarkListPage.js index e44d80fb0..484f2d6af 100644 --- a/coz-shopping/src/Page/BookmarkListPage.js +++ b/coz-shopping/src/Page/BookmarkListPage.js @@ -44,25 +44,61 @@ const ItemBox = styled.div` margin-top: 10px; ` -function BookmarkListPage ({ bookmark_List, setBookmark_List }) { +function BookmarkListPage ({ + bookmark_List, setBookmark_List }) { // 북마크 관련 전역 상태 const all_bookmark = JSON.parse(localStorage.getItem('bookmark')); - const [filter, setFilter] = useState(''); // 필터링 조건 - const [bookmarkPage_Items, setBookmarkPage] = useState([]); // 북마크 페이지 화면에 노출되는 데이터 - const [index, setIndex] = useState(4); // 화면엪 표시될 상품 index 관련 상태 + const [filter, setFilter] = useState(''); - // 🔴 배열의 index 값 이용해서 무한 스크롤 구현 중 -> 아래/위로 자유롭게 이동 가능하도록 구현 (스크롤 윗 부분도 알아볼 것) - // 상품 리스트도 동일한 로직 적용해서 수정 + // 1. 화면 마운트 -> 로컬 데이터를 전역 상태로 지정 + useEffect(() => {setBookmark_List(all_bookmark)}, []) - useEffect(() => { - const data = all_bookmark.filter((item, idx) => { + return ( + + +
+ +
+ + + {bookmark_List.map((item) => { + return () + })} + +
+ +
+ + + ) +} + +export default BookmarkListPage; + + +/** + * + * // 🔴 배열의 index 값 이용해서 무한 스크롤 구현 중 -> 아래/위로 자유롭게 이동 가능하도록 구현 (스크롤 윗 부분도 알아볼 것) + // 상품 리스트도 동일한 로직 적용해서 수정 + * + * 1. index 관련 상태 + * const [index, setIndex] = useState(4); // 화면엪 표시될 상품 index 관련 상태 + * + * + * 2. 마운트 시 useEffect + * const data = all_bookmark.filter((item, idx) => { return (idx 레퍼런스 참고해서 구현함 => 이를 활용해서 데이터 올바르게 처리할 로직 구현해야 함 (https://abangpa1ace.tistory.com/118) 참고 + 3. 무한 스크롤 관련 로직 + + // 무한 스크롤 -> 레퍼런스 참고해서 구현함 => 이를 활용해서 데이터 올바르게 처리할 로직 구현해야 함 (https://abangpa1ace.tistory.com/118) 참고 const handleScroll =() => { const { scrollHeight, scrollTop, clientHeight } = document.documentElement; @@ -88,28 +124,5 @@ function BookmarkListPage ({ bookmark_List, setBookmark_List }) { }, [index]) - - return ( - - -
- -
- - - {bookmarkPage_Items.map((item) => { - return () // 북마크 리스트 페이지에 렌더링 되는 데이터 (필터링에 따라 변경됨) - })} - -
- -
- - - ) -} -export default BookmarkListPage; \ No newline at end of file + */ \ No newline at end of file diff --git a/coz-shopping/src/Page/MainPage.js b/coz-shopping/src/Page/MainPage.js index 400d665fd..b98eb8472 100644 --- a/coz-shopping/src/Page/MainPage.js +++ b/coz-shopping/src/Page/MainPage.js @@ -18,7 +18,6 @@ function MainPage ({ bookmark_List, setBookmark_List }) { const [items, setItems] = useState([]); // 서버에서 받아온 상품 리스트 - useEffect(() => { const request = async () => { @@ -29,12 +28,9 @@ function MainPage ({ bookmark_List, setBookmark_List }) { } catch (error) { console.log('Response error', error); - } - } - - request(); - - }, []) + }} + + request();}, []) return ( From 242101c56a1391d2390d02a46e7a78647a3bf69c Mon Sep 17 00:00:00 2001 From: novice1993 Date: Fri, 14 Jul 2023 18:13:55 +0900 Subject: [PATCH 3/8] =?UTF-8?q?=EB=AC=B4=ED=95=9C=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=EA=B8=B0=EB=8A=A5=20=EC=9D=BC=EB=B6=80=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 위/아래 스크롤 움직임에 따라 화면에 렌더링 되는 아이템 개수 변경되도록 구현 (북마크 리스트 페이지) - 로직 미완성으로 인하여 일부 오류 발생 (BookmarkListPage 파일에 기입하여 놓음) - 수정 및 상품리스트 페이지에도 적용 예정 --- coz-shopping/src/Page/BookmarkListPage.js | 102 +++++++++++----------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/coz-shopping/src/Page/BookmarkListPage.js b/coz-shopping/src/Page/BookmarkListPage.js index 484f2d6af..af84309d4 100644 --- a/coz-shopping/src/Page/BookmarkListPage.js +++ b/coz-shopping/src/Page/BookmarkListPage.js @@ -49,9 +49,57 @@ function BookmarkListPage ({ const all_bookmark = JSON.parse(localStorage.getItem('bookmark')); const [filter, setFilter] = useState(''); + const [index, setIndex] = useState(0); // 렌더링 될 상품 index 관련 상태 + + + // 🔴 현재 스크롤 움직임에 따라 (top, bottom) index 상태가 변경 -> 화면에 렌더링 되는 아이템 개수도 변경되고 있음 + // 🔴 변경해야 하는 점 -> index를 전체 개수에 맞추다보니 -> 필터링 걸었을 때도 해당 조건에 맞추어 변경됨 -> 필터에 해당하는 아이템 개수가 8개 미만이어도 index 값을 증가시킴 + // => filter 상태 활용하여 수정 필요함 + + useEffect(() => { + setIndex(index+8) + }, []) + + useEffect(() => { // index 변화 -> 화면에 렌더링 되는 아이템 idx도 변화 (화면 scroll과 연동) + + // 1) 필터링 설정 안하거나 2) 전체 선택했을 때 + if(filter === '' || filter === 'all'){ + const data = all_bookmark.filter((item, idx) => (index-8 <= idx && idx < index)) + setBookmark_List(data)} + + // 2) 특정 필터링 설정했을 때 + else { + const filtered_data = all_bookmark.filter((item) => item.type === filter); + const data = filtered_data.filter((item, idx) => (index-8 <= idx && idx < index)); + setBookmark_List(data)} + + }, [index, filter]) + + + // 무한 스크롤 -> 레퍼런스 참고해서 구현함 => 이를 활용해서 데이터 올바르게 처리할 로직 구현해야 함 (https://abangpa1ace.tistory.com/118) 참고 + const handleScroll =() => { + + const { scrollHeight, scrollTop, clientHeight } = document.documentElement; + + if(scrollTop === 0){ + console.log('top'); + + (0 < index-8) && setIndex(index-8); + window.scrollTo(0,1); + } + + if (scrollTop + clientHeight >= scrollHeight) { + console.log('bottom'); + + (index < all_bookmark.length) && setIndex(index+8) + window.scrollTo(0, scrollTop-1) + } + } + + useEffect(() => { + window.addEventListener('scroll', handleScroll); + return () => window.removeEventListener('scroll', handleScroll);}, [handleScroll]) - // 1. 화면 마운트 -> 로컬 데이터를 전역 상태로 지정 - useEffect(() => {setBookmark_List(all_bookmark)}, []) return ( @@ -77,52 +125,4 @@ function BookmarkListPage ({ ) } -export default BookmarkListPage; - - -/** - * - * // 🔴 배열의 index 값 이용해서 무한 스크롤 구현 중 -> 아래/위로 자유롭게 이동 가능하도록 구현 (스크롤 윗 부분도 알아볼 것) - // 상품 리스트도 동일한 로직 적용해서 수정 - * - * 1. index 관련 상태 - * const [index, setIndex] = useState(4); // 화면엪 표시될 상품 index 관련 상태 - * - * - * 2. 마운트 시 useEffect - * const data = all_bookmark.filter((item, idx) => { - return (idx 레퍼런스 참고해서 구현함 => 이를 활용해서 데이터 올바르게 처리할 로직 구현해야 함 (https://abangpa1ace.tistory.com/118) 참고 - const handleScroll =() => { - - const { scrollHeight, scrollTop, clientHeight } = document.documentElement; - - if (scrollTop + clientHeight >= scrollHeight) { - if(index < all_bookmark.length){ - setIndex(index+4);} - - window.scrollTo(0, scrollTop-1) - } - } - - useEffect(() => { - window.addEventListener('scroll', handleScroll); - return () => window.removeEventListener('scroll', handleScroll); - }, [handleScroll]) - - useEffect(() => { - const data = all_bookmark.filter((item, idx) => { - return (idx>index-5 && idx Date: Fri, 14 Jul 2023 23:31:47 +0900 Subject: [PATCH 4/8] =?UTF-8?q?=EB=AC=B4=ED=95=9C=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=EA=B5=AC=ED=98=84=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - BookmarkListPage 무한스크롤 구현 완료 - ItemListPage 에서도 무한스크롤 적용되었으나, 일부 오류 발생 (필터 변경 시 오류 발생) - 오류 수정 후 토스트 ui 구현 예정 --- coz-shopping/src/Component/BookmarkItem.js | 29 ++++- coz-shopping/src/Component/Item.js | 6 +- .../Component/MainComponent/BookmarkList.js | 7 +- coz-shopping/src/Page/BookmarkListPage.js | 50 +++++---- coz-shopping/src/Page/ItemListPage.js | 106 ++++++++++-------- 5 files changed, 116 insertions(+), 82 deletions(-) diff --git a/coz-shopping/src/Component/BookmarkItem.js b/coz-shopping/src/Component/BookmarkItem.js index 30f6b6d63..72e836708 100644 --- a/coz-shopping/src/Component/BookmarkItem.js +++ b/coz-shopping/src/Component/BookmarkItem.js @@ -59,7 +59,8 @@ const Followers = styled.div` function BookmarkItem ({ bookmarkItem, // 렌더링 할 개별 아이템 - bookmark_List, setBookmark_List // 북마크 전역상태, 상태관리 함수 + bookmark_List, setBookmark_List, + all_bookmark, index, filter, // 1) 로컬 스토리지 (북마크 리스트) 2) 렌더링할 아이템 기준 index 3) 필터링 조건 }) { const [bookmark, setBookmark] = useState(true); @@ -69,17 +70,33 @@ function BookmarkItem ({ const modalButtonClick = () => { setModal(!modal); } - // 2. 북마크 취소 -> 1) 로컬 스토리지 데이터 갱신 2) 전역 상태 변경 ( 북마크 리스트에서 해당 아이템 삭제 ) + // 북마크 취소 -> 1) 로컬 스토리지 데이터 갱신 2) 전역 상태 변경 ( 북마크 리스트에서 해당 아이템 삭제 ) useEffect(() => { if(!bookmark){ - const bookmarData = (bookmark_List.filter((item) => item.id !== bookmarkItem.id)) + const bookmarData = (all_bookmark.filter((item) => item.id !== bookmarkItem.id)) + + // 1. MainPage의 BookmarkList에서 아이템 삭제했을 때 + if (filter === undefined) { + localStorage.setItem('bookmark', JSON.stringify(bookmarData)); + setBookmark_List(bookmarData) + } + + // 2. BookmarkListPage 에서 아이템 삭제했을 때 -> filter 조건에 맞춰서 렌더링 설정 + else { + if(filter === '' || filter === 'all'){ + const data = bookmarData.filter((item, idx) => (index-8 <= idx && idx < index)) + setBookmark_List(data)} + + else { + const filtered = bookmarData.filter((item) => item.type === filter); + const filtered_data = filtered.filter((item, idx) => (index-8 <= idx && idx < index)); + setBookmark_List(filtered_data)} + } - localStorage.setItem('bookmark', JSON.stringify(bookmarData)); - setBookmark_List(bookmarData) - }}, [bookmark]) + return ( <> diff --git a/coz-shopping/src/Component/Item.js b/coz-shopping/src/Component/Item.js index 0861771b9..02b5a448d 100644 --- a/coz-shopping/src/Component/Item.js +++ b/coz-shopping/src/Component/Item.js @@ -69,19 +69,17 @@ function Item ({ item, bookmark_List, setBookmark_List }) { (check !== undefined) && setBookmark(true)}, [item]) - useEffect(() => { // 신규 등록 혹은 해제 -> 1) 로컬 데이터 갱신 2) 북마크 전역상태 갱신 + useEffect(() => { // 북마크 신규 등록 or 해제 -> 1) 로컬 데이터 갱신 2) 북마크 전역상태 갱신 if(bookmark === true && check === undefined){ const newData = [...bookmark_List, item] - localStorage.setItem('bookmark', JSON.stringify(newData)); setBookmark_List(newData); } else if (bookmark === false) { - - const newData = bookmark_List.filter((bookmarkItem) => {return bookmarkItem.id !== item.id}); + const newData = bookmark_List.filter((bookmarkItem) => {return bookmarkItem.id !== item.id}); localStorage.setItem('bookmark', JSON.stringify(newData)); setBookmark_List(newData) } diff --git a/coz-shopping/src/Component/MainComponent/BookmarkList.js b/coz-shopping/src/Component/MainComponent/BookmarkList.js index 31918dd6a..07496e135 100644 --- a/coz-shopping/src/Component/MainComponent/BookmarkList.js +++ b/coz-shopping/src/Component/MainComponent/BookmarkList.js @@ -50,8 +50,9 @@ const Emptybox = styled.div` function BookmarkList ({ bookmark_List, setBookmark_List }) { // MainPage로 이동 시 -> 로컬 스토리지에 있는 전체 북마크 리스트를 화면에 불러옴 + const all_bookmark = JSON.parse(localStorage.getItem('bookmark')); + useEffect(() => { - const all_bookmark = JSON.parse(localStorage.getItem('bookmark')); setBookmark_List(all_bookmark); }, []) @@ -61,7 +62,9 @@ function BookmarkList ({ bookmark_List, setBookmark_List }) { { (bookmark_List.length !== 0) ? bookmark_List.map((bookmarkItem, idx) => { - return (idx < 4) && + return (idx < 4) && }) : 상품이 없습니다 } diff --git a/coz-shopping/src/Page/BookmarkListPage.js b/coz-shopping/src/Page/BookmarkListPage.js index af84309d4..ff40fb0f0 100644 --- a/coz-shopping/src/Page/BookmarkListPage.js +++ b/coz-shopping/src/Page/BookmarkListPage.js @@ -45,53 +45,57 @@ const ItemBox = styled.div` ` function BookmarkListPage ({ - bookmark_List, setBookmark_List }) { // 북마크 관련 전역 상태 + bookmark_List, setBookmark_List }) { const all_bookmark = JSON.parse(localStorage.getItem('bookmark')); const [filter, setFilter] = useState(''); - const [index, setIndex] = useState(0); // 렌더링 될 상품 index 관련 상태 + const [index, setIndex] = useState(0); // 화면에 표시할 아이템 개수 관련 상태 + useEffect(() => {setIndex(8) }, []) // 화면에 표시할 아이템 개수 - // 🔴 현재 스크롤 움직임에 따라 (top, bottom) index 상태가 변경 -> 화면에 렌더링 되는 아이템 개수도 변경되고 있음 - // 🔴 변경해야 하는 점 -> index를 전체 개수에 맞추다보니 -> 필터링 걸었을 때도 해당 조건에 맞추어 변경됨 -> 필터에 해당하는 아이템 개수가 8개 미만이어도 index 값을 증가시킴 - // => filter 상태 활용하여 수정 필요함 - - useEffect(() => { - setIndex(index+8) - }, []) - - useEffect(() => { // index 변화 -> 화면에 렌더링 되는 아이템 idx도 변화 (화면 scroll과 연동) + + useEffect(() => { // index 혹은 filter 변경 -> 화면에 렌더링 되는 아이템 변화 (scroll 움직임과 연동) - // 1) 필터링 설정 안하거나 2) 전체 선택했을 때 + // 1) 필터링 설정 안하거나 or '전체' 선택했을 때 if(filter === '' || filter === 'all'){ const data = all_bookmark.filter((item, idx) => (index-8 <= idx && idx < index)) setBookmark_List(data)} // 2) 특정 필터링 설정했을 때 else { - const filtered_data = all_bookmark.filter((item) => item.type === filter); - const data = filtered_data.filter((item, idx) => (index-8 <= idx && idx < index)); - setBookmark_List(data)} + setIndex(8); // index 값 초기화 + + const filtered = all_bookmark.filter((item) => item.type === filter); + const filtered_data = filtered.filter((item, idx) => (index-8 <= idx && idx < index)); + setBookmark_List(filtered_data)} }, [index, filter]) - // 무한 스크롤 -> 레퍼런스 참고해서 구현함 => 이를 활용해서 데이터 올바르게 처리할 로직 구현해야 함 (https://abangpa1ace.tistory.com/118) 참고 - const handleScroll =() => { + const handleScroll =() => { // 스크롤 위,아래로 이동 -> 렌더링되는 아이템 변경 const { scrollHeight, scrollTop, clientHeight } = document.documentElement; if(scrollTop === 0){ - console.log('top'); (0 < index-8) && setIndex(index-8); window.scrollTo(0,1); } - if (scrollTop + clientHeight >= scrollHeight) { - console.log('bottom'); + if (scrollTop + clientHeight >= scrollHeight) { + + let standard_Length; // filter에 따라 렌더링 기준이 되는 index 다르게 적용 + + if (filter === '' || filter === 'all') { + standard_Length = all_bookmark.length } - (index < all_bookmark.length) && setIndex(index+8) + else { + const filtered = all_bookmark.filter((item) => item.type === filter); + const filtered_data = filtered.filter((item, idx) => (index-8 <= idx && idx < index)); + + standard_Length = filtered_data.length;} + + (index < standard_Length) && setIndex(index+8); window.scrollTo(0, scrollTop-1) } } @@ -113,8 +117,8 @@ function BookmarkListPage ({ {bookmark_List.map((item) => { return () + bookmarkItem={item} bookmark_List={bookmark_List} setBookmark_List={setBookmark_List} + all_bookmark={all_bookmark} index={index} filter={filter}/>) })}
diff --git a/coz-shopping/src/Page/ItemListPage.js b/coz-shopping/src/Page/ItemListPage.js index e3e8b362e..3ba3ff14a 100644 --- a/coz-shopping/src/Page/ItemListPage.js +++ b/coz-shopping/src/Page/ItemListPage.js @@ -47,27 +47,66 @@ const ItemBox = styled.div` function ItemListPage ({ bookmark_List, setBookmark_List }) { const [items, setItems] = useState([]); // 서버에서 받아오는 상품 데이터 - const [filter, setFilter] = useState(''); // 필터링 조건 + const [filter, setFilter] = useState(''); + const [index, setIndex] = useState(0); // 화면에 표시할 아이템 개수 관련 상태 + const all_Items = JSON.parse(localStorage.getItem('all_Items')); // 로컬에 저장한 상품 데이터 - useEffect(() => { + useEffect(() => {setIndex(8)}, []) // 화면에 표시할 아이템 개수 + useState(() => { setIndex(8)}, [filter]) // 필터 변경 -> index 초기화 + + + useEffect(() => { // index 혹은 filter 변경 -> 화면에 렌더링 되는 아이템 변화 (scroll 움직임과 연동) + + const request = async () => { + try { + + // 1. index가 변경되면 -> 서버에서 데이터를 받아오고 + const res = await fetch('http://cozshopping.codestates-seb.link/api/v1/products?count=8') + const data = await res.json(); + + // 2. 기존에 저장했던 데이터를 불러와서 + const previousItem = JSON.parse(localStorage.getItem('all_Items')); + + // 3-1. 저장했던 데이터가 있을 경우 + if(previousItem !== null){ + // 중복 체크를 시행함 + const newItem = data.filter((item) => { + let result = 0; + for(let i=0; i 로컬 데이터에 저장 + const newItemList = [...previousItem, ...newItem] + localStorage.setItem('all_Items', JSON.stringify(newItemList)); - const request = async () => { - try { - const res = await fetch('http://cozshopping.codestates-seb.link/api/v1/products?count=8') - const data = await res.json(); + // 3-22. 저장했던 데이터가 없을 경우 + } else { + // 서버에서 받아온 데이터 저장 + localStorage.setItem('all_Items', JSON.stringify(data));} - localStorage.setItem('all_Items', JSON.stringify(data)); // 불러온 데이터 로컬 스토리지에 저장 - setItems(data); - } catch (error) { - console.log('Response error', error); + + if(filter === '' || filter === 'all'){ + const renderingItems = all_Items.filter((item, idx) => (index-8 <= idx && idx < index)) + setItems(renderingItems); + } else { + const filtered = all_Items.filter((item) => item.type === filter); + const filtered_data = filtered.filter((item, idx) => (index-8 <= idx && idx < index)); + setItems(filtered_data) } + + + + } catch (error) { + console.log('Response error', error); } - - request(); - - }, []) + } + + request(); + + }, [index]) // 무한 스크롤 -> 레퍼런스 참고해서 구현함 => 이를 활용해서 데이터 올바르게 처리할 로직 구현해야 함 (https://abangpa1ace.tistory.com/118) 참고 @@ -75,40 +114,13 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { const { scrollHeight, scrollTop, clientHeight } = document.documentElement; - if (scrollTop + clientHeight >= scrollHeight) { + if(scrollTop === 0){ + (0 < index-8) && setIndex(index-8); + window.scrollTo(0,1)} - const request = async () => { - try { - const res = await fetch('http://cozshopping.codestates-seb.link/api/v1/products?count=8') - const data = await res.json(); - - const previousItem = JSON.parse(localStorage.getItem('all_Items')); // 1) 기존에 로컬에 저장한 상품 데이터 - - console.log(previousItem); - - const newItem = data.filter((item) => { // 2) 기존 데이터 - 새로 불러온 데이터 : 중복 검사 - let result = 0; - for(let i=0; i 로컬에 저장 - localStorage.setItem('all_Items', JSON.stringify(newItemList)); - - (filter === '' || filter === 'all') ? setItems(newItemList) // 4) 현재 필터 고려 -> 렌더링 될 상태로 설정 - : setItems(newItemList.filter((item) => item.type === filter)) - - } catch (error) { - console.log('Response error', error); - } - } - - request(); - - window.scrollTo(0, scrollTop-1) - } + if (scrollTop + clientHeight >= scrollHeight) { + setIndex(index+8); + window.scrollTo(0, scrollTop-1)} } useEffect(() => { From a2260cac7e5dd294fa108438cb15ba96e16e9d61 Mon Sep 17 00:00:00 2001 From: novice1993 Date: Sat, 15 Jul 2023 01:26:23 +0900 Subject: [PATCH 5/8] =?UTF-8?q?=EB=AC=B4=ED=95=9C=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A1=A4=20=EA=B5=AC=ED=98=84=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - BookmarkListPage, ItemListPage 모두 무한 스크롤 구현 완료 - 스크롤을 위/아래로 움직였을 때 상품 아이템 렌더링 변경됨 --- coz-shopping/src/Component/ItemFilter.js | 20 ++++++++++--- coz-shopping/src/Page/BookmarkListPage.js | 16 ++++++---- coz-shopping/src/Page/ItemListPage.js | 36 +++++++++++++---------- 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/coz-shopping/src/Component/ItemFilter.js b/coz-shopping/src/Component/ItemFilter.js index a6e54a1b9..d5f9eee56 100644 --- a/coz-shopping/src/Component/ItemFilter.js +++ b/coz-shopping/src/Component/ItemFilter.js @@ -36,14 +36,26 @@ const Text = styled.div` function ItemFilter ({ filter, setFilter, // 필터 관련 상태 setItems, // 북마크 전역 상태관리 함수 - all_Items // 로컬 스토리지 데이터 + all_Items, // 로컬 스토리지 데이터 + index }) { useEffect(() => { // 필터를 변경했을 때 - (filter === 'all') ? setItems(all_Items) // if) 전체 데이터 : 북마크 전역 상태를 로컬 스토리지 데이터로 변경 - : setItems(all_Items.filter((item) => item.type === filter)) // if-2) 특정 조건 : 로컬 스토리지 데이터를 필터링 해서 전역 상태로 설정 - + if(filter === '' || filter === 'all'){ + const renderingItems = all_Items.filter((item, idx) => (index-8 <= idx && idx < index)) + + console.log(index); + setItems(renderingItems); + + } else { + const filtered = all_Items.filter((item) => item.type === filter); + const filtered_data = filtered.filter((item, idx) => (index-8 <= idx && idx < index)); + + console.log(index); + setItems(filtered_data) + } + }, [filter]) diff --git a/coz-shopping/src/Page/BookmarkListPage.js b/coz-shopping/src/Page/BookmarkListPage.js index ff40fb0f0..619f8d3ac 100644 --- a/coz-shopping/src/Page/BookmarkListPage.js +++ b/coz-shopping/src/Page/BookmarkListPage.js @@ -51,25 +51,29 @@ function BookmarkListPage ({ const [filter, setFilter] = useState(''); const [index, setIndex] = useState(0); // 화면에 표시할 아이템 개수 관련 상태 - useEffect(() => {setIndex(8) }, []) // 화면에 표시할 아이템 개수 + useEffect(() => {setIndex(8)}, []) // 화면에 표시할 아이템 개수 + useEffect(() => {setIndex(8)}, [filter]) // filter 변경 -> index 초기화 + - useEffect(() => { // index 혹은 filter 변경 -> 화면에 렌더링 되는 아이템 변화 (scroll 움직임과 연동) + // 1) 필터링 설정 안하거나 or '전체' 선택했을 때 if(filter === '' || filter === 'all'){ const data = all_bookmark.filter((item, idx) => (index-8 <= idx && idx < index)) + + console.log(data); setBookmark_List(data)} // 2) 특정 필터링 설정했을 때 else { - setIndex(8); // index 값 초기화 - const filtered = all_bookmark.filter((item) => item.type === filter); const filtered_data = filtered.filter((item, idx) => (index-8 <= idx && idx < index)); + + console.log(filtered_data); setBookmark_List(filtered_data)} - }, [index, filter]) + }, [index]) const handleScroll =() => { // 스크롤 위,아래로 이동 -> 렌더링되는 아이템 변경 @@ -112,7 +116,7 @@ function BookmarkListPage ({
+ filter={filter} setFilter={setFilter} bookmark_List={bookmark_List} setItems={setBookmark_List} all_Items={all_bookmark} index={index} /> {bookmark_List.map((item) => { return ( {setIndex(8)}, []) // 화면에 표시할 아이템 개수 - useState(() => { setIndex(8)}, [filter]) // 필터 변경 -> index 초기화 + useEffect(() => { setIndex(8)}, [filter]) // 필터 변경 -> index 초기화 useEffect(() => { // index 혹은 filter 변경 -> 화면에 렌더링 되는 아이템 변화 (scroll 움직임과 연동) @@ -86,19 +86,6 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { // 서버에서 받아온 데이터 저장 localStorage.setItem('all_Items', JSON.stringify(data));} - - - if(filter === '' || filter === 'all'){ - const renderingItems = all_Items.filter((item, idx) => (index-8 <= idx && idx < index)) - setItems(renderingItems); - } else { - const filtered = all_Items.filter((item) => item.type === filter); - const filtered_data = filtered.filter((item, idx) => (index-8 <= idx && idx < index)); - setItems(filtered_data) - } - - - } catch (error) { console.log('Response error', error); } @@ -106,6 +93,17 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { request(); + if(filter === '' || filter === 'all'){ + const renderingItems = all_Items.filter((item, idx) => (index-8 <= idx && idx < index)) + + setItems(renderingItems); + } else { + const filtered = all_Items.filter((item) => item.type === filter); + const filtered_data = filtered.filter((item, idx) => (index-8 <= idx && idx < index)); + + setItems(filtered_data) + } + }, [index]) @@ -119,8 +117,14 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { window.scrollTo(0,1)} if (scrollTop + clientHeight >= scrollHeight) { + + if(items.length < 1){ // 더 이상 렌더링할 아이템이 없을 경우 -> index를 증가시키지 않음 + setIndex(index-8); + return; + } + setIndex(index+8); - window.scrollTo(0, scrollTop-1)} + window.scrollTo(0, scrollTop-5)} } useEffect(() => { @@ -136,7 +140,7 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) {
- + {items.map((item) => { return From 251f6c28e39ebf05559ecf5f84133464a1c65f62 Mon Sep 17 00:00:00 2001 From: novice1993 Date: Sat, 15 Jul 2023 02:13:22 +0900 Subject: [PATCH 6/8] =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 무한 스크롤 관련 오류 수정 --- coz-shopping/src/App.css | 2 +- coz-shopping/src/Component/ItemFilter.js | 26 +---------------------- coz-shopping/src/Page/BookmarkListPage.js | 5 ++--- coz-shopping/src/Page/ItemListPage.js | 17 ++++++++------- 4 files changed, 13 insertions(+), 37 deletions(-) diff --git a/coz-shopping/src/App.css b/coz-shopping/src/App.css index 37a4c9b25..d0081d120 100644 --- a/coz-shopping/src/App.css +++ b/coz-shopping/src/App.css @@ -29,6 +29,6 @@ footer { } div { - border: 1px solid black; + /* border: 1px solid black; */ } diff --git a/coz-shopping/src/Component/ItemFilter.js b/coz-shopping/src/Component/ItemFilter.js index d5f9eee56..f5360cdad 100644 --- a/coz-shopping/src/Component/ItemFilter.js +++ b/coz-shopping/src/Component/ItemFilter.js @@ -33,31 +33,7 @@ const Text = styled.div` text-align: center; ` -function ItemFilter ({ - filter, setFilter, // 필터 관련 상태 - setItems, // 북마크 전역 상태관리 함수 - all_Items, // 로컬 스토리지 데이터 - index -}) { - - useEffect(() => { // 필터를 변경했을 때 - - if(filter === '' || filter === 'all'){ - const renderingItems = all_Items.filter((item, idx) => (index-8 <= idx && idx < index)) - - console.log(index); - setItems(renderingItems); - - } else { - const filtered = all_Items.filter((item) => item.type === filter); - const filtered_data = filtered.filter((item, idx) => (index-8 <= idx && idx < index)); - - console.log(index); - setItems(filtered_data) - } - - }, [filter]) - +function ItemFilter ({ setFilter }) { return ( diff --git a/coz-shopping/src/Page/BookmarkListPage.js b/coz-shopping/src/Page/BookmarkListPage.js index 619f8d3ac..a31ef513e 100644 --- a/coz-shopping/src/Page/BookmarkListPage.js +++ b/coz-shopping/src/Page/BookmarkListPage.js @@ -73,7 +73,7 @@ function BookmarkListPage ({ console.log(filtered_data); setBookmark_List(filtered_data)} - }, [index]) + }, [index, filter]) const handleScroll =() => { // 스크롤 위,아래로 이동 -> 렌더링되는 아이템 변경 @@ -115,8 +115,7 @@ function BookmarkListPage ({
- + {bookmark_List.map((item) => { return ( { // index 혹은 filter 변경 -> 화면에 렌더링 되는 아이템 변화 (scroll 움직임과 연동) + + console.log(index); const request = async () => { try { @@ -95,21 +97,20 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { if(filter === '' || filter === 'all'){ const renderingItems = all_Items.filter((item, idx) => (index-8 <= idx && idx < index)) - setItems(renderingItems); } else { const filtered = all_Items.filter((item) => item.type === filter); const filtered_data = filtered.filter((item, idx) => (index-8 <= idx && idx < index)); - setItems(filtered_data) } - }, [index]) - + }, [index, filter]) // 무한 스크롤 -> 레퍼런스 참고해서 구현함 => 이를 활용해서 데이터 올바르게 처리할 로직 구현해야 함 (https://abangpa1ace.tistory.com/118) 참고 const handleScroll =() => { + console.log('스크롤 이벤트 발생 중') + const { scrollHeight, scrollTop, clientHeight } = document.documentElement; if(scrollTop === 0){ @@ -118,12 +119,12 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { if (scrollTop + clientHeight >= scrollHeight) { - if(items.length < 1){ // 더 이상 렌더링할 아이템이 없을 경우 -> index를 증가시키지 않음 + if(items.length === 0 || document.documentElement.scrollHeight <= document.documentElement.clientHeight){ // 더 이상 렌더링할 아이템이 없을 경우 -> index를 증가시키지 않음 setIndex(index-8); return; + } else { + setIndex(index+8); } - - setIndex(index+8); window.scrollTo(0, scrollTop-5)} } @@ -140,7 +141,7 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) {
- + {items.map((item) => { return From 38469b5aecd6af94907cef6dedf559b0ec07ed6a Mon Sep 17 00:00:00 2001 From: novice1993 Date: Sun, 16 Jul 2023 03:32:01 +0900 Subject: [PATCH 7/8] =?UTF-8?q?=ED=86=A0=EC=8A=A4=ED=8A=B8=20=EB=A9=94?= =?UTF-8?q?=EC=84=B8=EC=A7=80=20=EC=9D=BC=EB=B6=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Mainpage의 북마크 리스트의 북마크 버튼 누를 시 토스트 메세지 생성됨 - 추가적인 디자인 적용 필요한 상황임 (디자인 적용 완료 시, 이외의 부분도 구현 완료 예정) - 자세한 내용은 MainPage 파일에 기입해놓음 --- coz-shopping/src/App.css | 2 +- coz-shopping/src/App.js | 3 ++ coz-shopping/src/Component/BookmarkItem.js | 26 ++++++++---- coz-shopping/src/Component/Item.js | 13 ++++-- .../Component/MainComponent/BookmarkList.js | 10 ++--- .../src/Component/MainComponent/Footer.js | 5 +++ coz-shopping/src/Component/Toast.js | 42 +++++++++++++++++++ coz-shopping/src/Page/BookmarkListPage.js | 11 ++--- coz-shopping/src/Page/ItemListPage.js | 10 ++--- coz-shopping/src/Page/MainPage.js | 28 ++++++++++++- 10 files changed, 118 insertions(+), 32 deletions(-) create mode 100644 coz-shopping/src/Component/Toast.js diff --git a/coz-shopping/src/App.css b/coz-shopping/src/App.css index d0081d120..37a4c9b25 100644 --- a/coz-shopping/src/App.css +++ b/coz-shopping/src/App.css @@ -29,6 +29,6 @@ footer { } div { - /* border: 1px solid black; */ + border: 1px solid black; } diff --git a/coz-shopping/src/App.js b/coz-shopping/src/App.js index 8811e8766..9874cb519 100644 --- a/coz-shopping/src/App.js +++ b/coz-shopping/src/App.js @@ -11,6 +11,9 @@ function App() { const bookmarkData = JSON.parse(localStorage.getItem('bookmark')); const [bookmark_List, setBookmark_List] = useState( (bookmarkData !== null) ? bookmarkData : [] ); + + + return ( diff --git a/coz-shopping/src/Component/BookmarkItem.js b/coz-shopping/src/Component/BookmarkItem.js index 72e836708..297b18f70 100644 --- a/coz-shopping/src/Component/BookmarkItem.js +++ b/coz-shopping/src/Component/BookmarkItem.js @@ -60,14 +60,18 @@ const Followers = styled.div` function BookmarkItem ({ bookmarkItem, // 렌더링 할 개별 아이템 bookmark_List, setBookmark_List, - all_bookmark, index, filter, // 1) 로컬 스토리지 (북마크 리스트) 2) 렌더링할 아이템 기준 index 3) 필터링 조건 + all_bookmark, index, filter, // 1) 로컬 스토리지 (북마크 리스트) 2) 렌더링할 아이템 기준 index 3) 필터링 조건 + setToast, setToastContent }) { const [bookmark, setBookmark] = useState(true); const [modal, setModal] = useState(false); - const bookmarkButtonClick = () => { setBookmark(!bookmark); } - const modalButtonClick = () => { setModal(!modal); } + const bookmarkButtonClick = () => { + setBookmark(!bookmark) + setToast(true)} + + const modalButtonClick = () => { setModal(!modal) } // 북마크 취소 -> 1) 로컬 스토리지 데이터 갱신 2) 전역 상태 변경 ( 북마크 리스트에서 해당 아이템 삭제 ) @@ -75,22 +79,26 @@ function BookmarkItem ({ if(!bookmark){ - const bookmarData = (all_bookmark.filter((item) => item.id !== bookmarkItem.id)) + setToastContent('상품이 북마크에서 제거되었습니다.'); + setTimeout(() => { setToast(false) }, 2000); + + + const bookmarkData = (all_bookmark.filter((item) => item.id !== bookmarkItem.id)) // 갱신된 북마크 리스트 (북마크 해제한 아이템 제외) + localStorage.setItem('bookmark', JSON.stringify(bookmarkData)); // 1. MainPage의 BookmarkList에서 아이템 삭제했을 때 if (filter === undefined) { - localStorage.setItem('bookmark', JSON.stringify(bookmarData)); - setBookmark_List(bookmarData) - } + // localStorage.setItem('bookmark', JSON.stringify(bookmarkData)); + setBookmark_List(bookmarkData)} // 2. BookmarkListPage 에서 아이템 삭제했을 때 -> filter 조건에 맞춰서 렌더링 설정 else { if(filter === '' || filter === 'all'){ - const data = bookmarData.filter((item, idx) => (index-8 <= idx && idx < index)) + const data = bookmarkData.filter((item, idx) => (index-8 <= idx && idx < index)) setBookmark_List(data)} else { - const filtered = bookmarData.filter((item) => item.type === filter); + const filtered = bookmarkData.filter((item) => item.type === filter); const filtered_data = filtered.filter((item, idx) => (index-8 <= idx && idx < index)); setBookmark_List(filtered_data)} } diff --git a/coz-shopping/src/Component/Item.js b/coz-shopping/src/Component/Item.js index 02b5a448d..844669b9b 100644 --- a/coz-shopping/src/Component/Item.js +++ b/coz-shopping/src/Component/Item.js @@ -62,7 +62,6 @@ function Item ({ item, bookmark_List, setBookmark_List }) { const check = bookmark_List.find((bookmakrItem) => bookmakrItem.id === item.id); // 이전에 북마크 등록된 아이템인지 체크 const bookmarkButtonClick = () => { setBookmark(!bookmark); } - const modalButtonClick = () => { setModal(true); } useEffect(() => { // item 정보 다시 불러왔을 때 -> 이전에 북마크 등록한 item일 경우 -> true값 부여 @@ -80,11 +79,19 @@ function Item ({ item, bookmark_List, setBookmark_List }) { } else if (bookmark === false) { const newData = bookmark_List.filter((bookmarkItem) => {return bookmarkItem.id !== item.id}); - localStorage.setItem('bookmark', JSON.stringify(newData)); - setBookmark_List(newData) + + // 상품 리스트에서 북마크 해제 했을 때 + if(bookmark_List.length !== newData.length){ + localStorage.setItem('bookmark', JSON.stringify(newData)); + setBookmark_List(newData) + } } }, [bookmark]) + // 북마크 리스트에서 북마크 해제했을 때 (상품 리스트 연동 해제) + useEffect(() => { + (check === undefined) && setBookmark(false)}, [bookmark_List]) + return ( <> diff --git a/coz-shopping/src/Component/MainComponent/BookmarkList.js b/coz-shopping/src/Component/MainComponent/BookmarkList.js index 07496e135..7fe874865 100644 --- a/coz-shopping/src/Component/MainComponent/BookmarkList.js +++ b/coz-shopping/src/Component/MainComponent/BookmarkList.js @@ -47,14 +47,11 @@ const Emptybox = styled.div` ` -function BookmarkList ({ bookmark_List, setBookmark_List }) { +function BookmarkList ({ bookmark_List, setBookmark_List, setToast, setToastContent }) { // MainPage로 이동 시 -> 로컬 스토리지에 있는 전체 북마크 리스트를 화면에 불러옴 const all_bookmark = JSON.parse(localStorage.getItem('bookmark')); - - useEffect(() => { - setBookmark_List(all_bookmark); - }, []) + useEffect(() => { setBookmark_List(all_bookmark) }, []) return ( @@ -64,7 +61,8 @@ function BookmarkList ({ bookmark_List, setBookmark_List }) { bookmark_List.map((bookmarkItem, idx) => { return (idx < 4) && + all_bookmark={all_bookmark} + setToast={setToast} setToastContent={setToastContent}/> }) : 상품이 없습니다 } diff --git a/coz-shopping/src/Component/MainComponent/Footer.js b/coz-shopping/src/Component/MainComponent/Footer.js index 0667a7aab..e04cacac3 100644 --- a/coz-shopping/src/Component/MainComponent/Footer.js +++ b/coz-shopping/src/Component/MainComponent/Footer.js @@ -20,9 +20,14 @@ const Content2 = styled.div` flex: 1 0 0; text-align: center; ` +const Test = styled.div` + text-align: center; + font-size: 1.5rem; +` function Footer () { + return ( 개인정보 처리방침 | 이용 약관 diff --git a/coz-shopping/src/Component/Toast.js b/coz-shopping/src/Component/Toast.js new file mode 100644 index 000000000..875780b47 --- /dev/null +++ b/coz-shopping/src/Component/Toast.js @@ -0,0 +1,42 @@ +import { styled } from "styled-components"; + +const Container = styled.div` + position: absolute; + transform: translate(1450px,650px); + display: none; + + &.notification { + display: block; + transition: transform 2s ease-in-out; + animation: toast-in-right 2s; + } + + @keyframes toast-in-right { + from { + transform: translate(1450px,650px); + } + to { + transform: translate(950px,650px); + } + } +` + +const Message = styled.div` + position: relative; + border: 1px solid black; + + background-color: blue; + color: white; + font-size: 2rem; +` + + +function Toast ({ toast, toastContent }) { + return ( + + {toastContent} + + ) +} + +export default Toast; \ No newline at end of file diff --git a/coz-shopping/src/Page/BookmarkListPage.js b/coz-shopping/src/Page/BookmarkListPage.js index a31ef513e..25236f563 100644 --- a/coz-shopping/src/Page/BookmarkListPage.js +++ b/coz-shopping/src/Page/BookmarkListPage.js @@ -20,7 +20,7 @@ const HeaderBox = styled.header` border-bottom: 1px solid black; ` -const FooterBox = styled.header` +const FooterBox = styled.div` flex: 1 0 0; ` @@ -56,8 +56,7 @@ function BookmarkListPage ({ useEffect(() => { // index 혹은 filter 변경 -> 화면에 렌더링 되는 아이템 변화 (scroll 움직임과 연동) - - + // 1) 필터링 설정 안하거나 or '전체' 선택했을 때 if(filter === '' || filter === 'all'){ const data = all_bookmark.filter((item, idx) => (index-8 <= idx && idx < index)) @@ -120,8 +119,10 @@ function BookmarkListPage ({ {bookmark_List.map((item) => { return () + bookmarkItem={item} // 1) 렌더링 할 개별 아이템 + bookmark_List={bookmark_List} setBookmark_List={setBookmark_List} // 2) 북마크 관련 전역 상태 -> 북마크 등록/삭제 연관 + all_bookmark={all_bookmark} index={index} filter={filter} + />) })}
diff --git a/coz-shopping/src/Page/ItemListPage.js b/coz-shopping/src/Page/ItemListPage.js index 162622653..fad204159 100644 --- a/coz-shopping/src/Page/ItemListPage.js +++ b/coz-shopping/src/Page/ItemListPage.js @@ -83,7 +83,7 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { const newItemList = [...previousItem, ...newItem] localStorage.setItem('all_Items', JSON.stringify(newItemList)); - // 3-22. 저장했던 데이터가 없을 경우 + // 3-2. 저장했던 데이터가 없을 경우 } else { // 서버에서 받아온 데이터 저장 localStorage.setItem('all_Items', JSON.stringify(data));} @@ -115,25 +115,23 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { if(scrollTop === 0){ (0 < index-8) && setIndex(index-8); - window.scrollTo(0,1)} + window.scrollTo(0,15)} if (scrollTop + clientHeight >= scrollHeight) { if(items.length === 0 || document.documentElement.scrollHeight <= document.documentElement.clientHeight){ // 더 이상 렌더링할 아이템이 없을 경우 -> index를 증가시키지 않음 setIndex(index-8); - return; } else { setIndex(index+8); } - window.scrollTo(0, scrollTop-5)} + window.scrollTo(0, scrollTop-15)} } useEffect(() => { window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, [handleScroll]) - - + return ( diff --git a/coz-shopping/src/Page/MainPage.js b/coz-shopping/src/Page/MainPage.js index b98eb8472..08f51cc67 100644 --- a/coz-shopping/src/Page/MainPage.js +++ b/coz-shopping/src/Page/MainPage.js @@ -4,6 +4,7 @@ import Header from "../Component/MainComponent/Header"; import Footer from "../Component/MainComponent/Footer"; import ItemList from "../Component/MainComponent/ItemList"; import BookmarkList from "../Component/MainComponent/BookmarkList"; +import Toast from "../Component/Toast"; const Main = styled.main` display: flex; @@ -14,9 +15,30 @@ const Container = styled.div` flex: 1 0 0; ` +// 🥦 Toast 메세지 구현 +// - MainPage의 북마크 리스트 일부 구현한 상황 +// - 북마크 버튼 눌렀을 때 토스트 메세지 뜸 +// - 북마크 별표 추가 + 색상 적용 필요 +// - Cmarket hooks 참고해서 opacity도 적용해보기 + +// 🥦 이상 완료 시 추가 진행할 부분 +// - MainPage의 아이템 리스트 +// - ItemListPage, BookmarkListPage 에도 적용 +// - 모두 완료했다면 디자인 적용 -> 버그 테스트 + + function MainPage ({ bookmark_List, setBookmark_List }) { const [items, setItems] = useState([]); // 서버에서 받아온 상품 리스트 + const [toast, setToast] = useState(false); // toast 메세지 띄울지 여부 + const [toastContent, setToastContent] = useState('테스트'); // toast에 들어가는 문구 + + + useEffect(() => { + console.log(toastContent)}, [toastContent]) + + useEffect(() => { + console.log(toast)}, [toast]) useEffect(() => { @@ -32,7 +54,6 @@ function MainPage ({ bookmark_List, setBookmark_List }) { request();}, []) - return ( <>
@@ -40,11 +61,14 @@ function MainPage ({ bookmark_List, setBookmark_List }) {
- + +
+ ); } From c235e4c0d6daef75c02b317d041ef23557f506b3 Mon Sep 17 00:00:00 2001 From: novice1993 Date: Mon, 17 Jul 2023 17:10:13 +0900 Subject: [PATCH 8/8] =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 디자인 및 토스트 ui까지 구현 완료 * 몇가지 수정 필요한 사항 1. 무한스크롤 구현 시 데이터 처리 - 현황 : 스크롤 이벤트가 발생할 때마다 서버에서 데이터를 받아옴 - 문제점 : 구현된 API의 제약으로 인해 받아올 수 있는 데이터의 개수 제한이 있음 - 한번에 8개씩만 받아오는 식으로 구현 중 - 화면에 렌더링되는 느낌이 좋지 않고 (직관적이지 않음) - 데이터를 매번 받아오는 것이 효율적인지 잘 모르겠음 - 개선방향 : 서버에서 데이터를 한번에 받아오는 방향으로 수정할지 고민 2. 토스트 ui 버그 - 현황 : 한번에 한개씩만 렌더링 되는 상황 - 문제점 : 다수의 북마크 변경이 발생할 시 로직이 꼬임 - 개선방향 : 다수의 토스트 메시지가 화면에 동시에 표현될 수 있도록 개선 필요 --- coz-shopping/.gitignore => .gitignore | 0 coz-shopping/README.md | 70 ------------------ coz-shopping/src/Component/Toast.js | 42 ----------- .../package-lock.json => package-lock.json | 0 coz-shopping/package.json => package.json | 0 {coz-shopping/public => public}/favicon.ico | Bin {coz-shopping/public => public}/index.html | 0 {coz-shopping/public => public}/manifest.json | 0 {coz-shopping/public => public}/robots.txt | 0 {coz-shopping/src => src}/App.css | 6 +- {coz-shopping/src => src}/App.js | 4 +- {coz-shopping/src => src}/App.test.js | 0 .../src => src}/Component/BookmarkItem.js | 36 +++++---- {coz-shopping/src => src}/Component/Item.js | 45 ++++++++--- .../src => src}/Component/ItemFilter.js | 0 .../Component/MainComponent/BookmarkList.js | 2 +- .../Component/MainComponent/Footer.js | 1 + .../Component/MainComponent/Header.js | 2 + .../Component/MainComponent/ItemList.js | 11 ++- .../Component/MainComponent/Menu.js | 25 ++++--- {coz-shopping/src => src}/Component/Modal.js | 19 ++++- src/Component/Toast.js | 55 ++++++++++++++ .../src => src}/Page/BookmarkListPage.js | 16 ++-- .../src => src}/Page/ItemListPage.js | 38 +++++----- {coz-shopping/src => src}/Page/MainPage.js | 34 ++++----- {coz-shopping/src => src}/img/all.jpg | Bin {coz-shopping/src => src}/img/brand.png | Bin {coz-shopping/src => src}/img/category.png | Bin {coz-shopping/src => src}/img/exhibition.png | Bin src/img/item.png | Bin 0 -> 352 bytes {coz-shopping/src => src}/img/logo.jpg | Bin {coz-shopping/src => src}/img/product.jpg | Bin {coz-shopping/src => src}/index.css | 0 {coz-shopping/src => src}/index.js | 0 {coz-shopping/src => src}/reportWebVitals.js | 0 {coz-shopping/src => src}/setupTests.js | 0 36 files changed, 201 insertions(+), 205 deletions(-) rename coz-shopping/.gitignore => .gitignore (100%) delete mode 100644 coz-shopping/README.md delete mode 100644 coz-shopping/src/Component/Toast.js rename coz-shopping/package-lock.json => package-lock.json (100%) rename coz-shopping/package.json => package.json (100%) rename {coz-shopping/public => public}/favicon.ico (100%) rename {coz-shopping/public => public}/index.html (100%) rename {coz-shopping/public => public}/manifest.json (100%) rename {coz-shopping/public => public}/robots.txt (100%) rename {coz-shopping/src => src}/App.css (90%) rename {coz-shopping/src => src}/App.js (95%) rename {coz-shopping/src => src}/App.test.js (100%) rename {coz-shopping/src => src}/Component/BookmarkItem.js (87%) rename {coz-shopping/src => src}/Component/Item.js (79%) rename {coz-shopping/src => src}/Component/ItemFilter.js (100%) rename {coz-shopping/src => src}/Component/MainComponent/BookmarkList.js (98%) rename {coz-shopping/src => src}/Component/MainComponent/Footer.js (95%) rename {coz-shopping/src => src}/Component/MainComponent/Header.js (93%) rename {coz-shopping/src => src}/Component/MainComponent/ItemList.js (57%) rename {coz-shopping/src => src}/Component/MainComponent/Menu.js (64%) rename {coz-shopping/src => src}/Component/Modal.js (74%) create mode 100644 src/Component/Toast.js rename {coz-shopping/src => src}/Page/BookmarkListPage.js (91%) rename {coz-shopping/src => src}/Page/ItemListPage.js (84%) rename {coz-shopping/src => src}/Page/MainPage.js (63%) rename {coz-shopping/src => src}/img/all.jpg (100%) rename {coz-shopping/src => src}/img/brand.png (100%) rename {coz-shopping/src => src}/img/category.png (100%) rename {coz-shopping/src => src}/img/exhibition.png (100%) create mode 100644 src/img/item.png rename {coz-shopping/src => src}/img/logo.jpg (100%) rename {coz-shopping/src => src}/img/product.jpg (100%) rename {coz-shopping/src => src}/index.css (100%) rename {coz-shopping/src => src}/index.js (100%) rename {coz-shopping/src => src}/reportWebVitals.js (100%) rename {coz-shopping/src => src}/setupTests.js (100%) diff --git a/coz-shopping/.gitignore b/.gitignore similarity index 100% rename from coz-shopping/.gitignore rename to .gitignore diff --git a/coz-shopping/README.md b/coz-shopping/README.md deleted file mode 100644 index 58beeaccd..000000000 --- a/coz-shopping/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# Getting Started with Create React App - -This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). - -## Available Scripts - -In the project directory, you can run: - -### `npm start` - -Runs the app in the development mode.\ -Open [http://localhost:3000](http://localhost:3000) to view it in your browser. - -The page will reload when you make changes.\ -You may also see any lint errors in the console. - -### `npm test` - -Launches the test runner in the interactive watch mode.\ -See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. - -### `npm run build` - -Builds the app for production to the `build` folder.\ -It correctly bundles React in production mode and optimizes the build for the best performance. - -The build is minified and the filenames include the hashes.\ -Your app is ready to be deployed! - -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. - -### `npm run eject` - -**Note: this is a one-way operation. Once you `eject`, you can't go back!** - -If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. - -Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. - -You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. - -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). - -### Code Splitting - -This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) - -### Analyzing the Bundle Size - -This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) - -### Making a Progressive Web App - -This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) - -### Advanced Configuration - -This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) - -### Deployment - -This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) - -### `npm run build` fails to minify - -This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) diff --git a/coz-shopping/src/Component/Toast.js b/coz-shopping/src/Component/Toast.js deleted file mode 100644 index 875780b47..000000000 --- a/coz-shopping/src/Component/Toast.js +++ /dev/null @@ -1,42 +0,0 @@ -import { styled } from "styled-components"; - -const Container = styled.div` - position: absolute; - transform: translate(1450px,650px); - display: none; - - &.notification { - display: block; - transition: transform 2s ease-in-out; - animation: toast-in-right 2s; - } - - @keyframes toast-in-right { - from { - transform: translate(1450px,650px); - } - to { - transform: translate(950px,650px); - } - } -` - -const Message = styled.div` - position: relative; - border: 1px solid black; - - background-color: blue; - color: white; - font-size: 2rem; -` - - -function Toast ({ toast, toastContent }) { - return ( - - {toastContent} - - ) -} - -export default Toast; \ No newline at end of file diff --git a/coz-shopping/package-lock.json b/package-lock.json similarity index 100% rename from coz-shopping/package-lock.json rename to package-lock.json diff --git a/coz-shopping/package.json b/package.json similarity index 100% rename from coz-shopping/package.json rename to package.json diff --git a/coz-shopping/public/favicon.ico b/public/favicon.ico similarity index 100% rename from coz-shopping/public/favicon.ico rename to public/favicon.ico diff --git a/coz-shopping/public/index.html b/public/index.html similarity index 100% rename from coz-shopping/public/index.html rename to public/index.html diff --git a/coz-shopping/public/manifest.json b/public/manifest.json similarity index 100% rename from coz-shopping/public/manifest.json rename to public/manifest.json diff --git a/coz-shopping/public/robots.txt b/public/robots.txt similarity index 100% rename from coz-shopping/public/robots.txt rename to public/robots.txt diff --git a/coz-shopping/src/App.css b/src/App.css similarity index 90% rename from coz-shopping/src/App.css rename to src/App.css index 37a4c9b25..aa0ff978f 100644 --- a/coz-shopping/src/App.css +++ b/src/App.css @@ -25,10 +25,10 @@ main { } footer { - flex: 1 0 0; + flex: 0.7 0 0; } -div { +/* div { border: 1px solid black; -} +} */ diff --git a/coz-shopping/src/App.js b/src/App.js similarity index 95% rename from coz-shopping/src/App.js rename to src/App.js index 9874cb519..21e01c7a5 100644 --- a/coz-shopping/src/App.js +++ b/src/App.js @@ -1,5 +1,5 @@ import './App.css'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import MainPage from './Page/MainPage'; import ItemListPage from './Page/ItemListPage'; import BookmarkListPage from './Page/BookmarkListPage'; @@ -12,8 +12,6 @@ function App() { const [bookmark_List, setBookmark_List] = useState( (bookmarkData !== null) ? bookmarkData : [] ); - - return ( diff --git a/coz-shopping/src/App.test.js b/src/App.test.js similarity index 100% rename from coz-shopping/src/App.test.js rename to src/App.test.js diff --git a/coz-shopping/src/Component/BookmarkItem.js b/src/Component/BookmarkItem.js similarity index 87% rename from coz-shopping/src/Component/BookmarkItem.js rename to src/Component/BookmarkItem.js index 297b18f70..aef5e91ea 100644 --- a/coz-shopping/src/Component/BookmarkItem.js +++ b/src/Component/BookmarkItem.js @@ -2,8 +2,15 @@ import { styled } from "styled-components"; import { useState, useEffect } from "react"; import Modal from "./Modal"; - // 전체 type 공통 적용 + +const Container = styled.div` + margin-left: 45px; + margin-right: 45px; + margin-top: 10px; + margin-bottom: 10px; +` + const ContentContainer = styled.div` display: flex; flex-direction: row; @@ -80,15 +87,13 @@ function BookmarkItem ({ if(!bookmark){ setToastContent('상품이 북마크에서 제거되었습니다.'); - setTimeout(() => { setToast(false) }, 2000); + setTimeout(() => { setToast(false) }, 3000); - const bookmarkData = (all_bookmark.filter((item) => item.id !== bookmarkItem.id)) // 갱신된 북마크 리스트 (북마크 해제한 아이템 제외) localStorage.setItem('bookmark', JSON.stringify(bookmarkData)); // 1. MainPage의 BookmarkList에서 아이템 삭제했을 때 if (filter === undefined) { - // localStorage.setItem('bookmark', JSON.stringify(bookmarkData)); setBookmark_List(bookmarkData)} // 2. BookmarkListPage 에서 아이템 삭제했을 때 -> filter 조건에 맞춰서 렌더링 설정 @@ -108,9 +113,14 @@ function BookmarkItem ({ return ( <> - {(modal) && } + {(modal) && + } + {(bookmarkItem.type === 'Product') && ( // product type -
+ { event.stopPropagation(); @@ -120,32 +130,32 @@ function BookmarkItem ({ {(bookmarkItem.discountPercentage !== null) && `${bookmarkItem.discountPercentage}%`} {parseInt(bookmarkItem.price).toLocaleString()}원 -
+ )} {(bookmarkItem.type === 'Category') && ( // Category type -
+ { event.stopPropagation(); bookmarkButtonClick()}} bookmark={bookmark}>★ # {bookmarkItem.title} -
+ )} {(bookmarkItem.type === 'Exhibition') && ( // Exhibition type -
+ { event.stopPropagation(); bookmarkButtonClick()}} bookmark={bookmark}>★ {bookmarkItem.title} {bookmarkItem.sub_title} -
+ )} {(bookmarkItem.type === 'Brand') && ( // Brand type -
+ { event.stopPropagation(); @@ -155,7 +165,7 @@ function BookmarkItem ({ 관심고객수 {parseInt(bookmarkItem.follower).toLocaleString()} -
+ )} ) diff --git a/coz-shopping/src/Component/Item.js b/src/Component/Item.js similarity index 79% rename from coz-shopping/src/Component/Item.js rename to src/Component/Item.js index 844669b9b..b811d9d3b 100644 --- a/coz-shopping/src/Component/Item.js +++ b/src/Component/Item.js @@ -3,6 +3,13 @@ import { useState, useEffect } from "react"; import Modal from "./Modal"; // 전체 type 공통 적용 +const Container = styled.div` + margin-left: 45px; + margin-right: 45px; + margin-top: 10px; + margin-bottom: 10px; +` + const ContentContainer = styled.div` display: flex; flex-direction: row; @@ -55,13 +62,17 @@ const Followers = styled.div` text-align: right; ` -function Item ({ item, bookmark_List, setBookmark_List }) { +// setToast={setToast} setToastContent={setToastContent} +function Item ({ item, bookmark_List, setBookmark_List, setToast, setToastContent }) { const [bookmark, setBookmark] = useState(false); const [modal, setModal] = useState(false); const check = bookmark_List.find((bookmakrItem) => bookmakrItem.id === item.id); // 이전에 북마크 등록된 아이템인지 체크 - const bookmarkButtonClick = () => { setBookmark(!bookmark); } + const bookmarkButtonClick = () => { + setBookmark(!bookmark) + setToast(true)} + const modalButtonClick = () => { setModal(true); } useEffect(() => { // item 정보 다시 불러왔을 때 -> 이전에 북마크 등록한 item일 경우 -> true값 부여 @@ -72,11 +83,17 @@ function Item ({ item, bookmark_List, setBookmark_List }) { if(bookmark === true && check === undefined){ + setToastContent('상품이 북마크에 추가되었습니다.'); + setTimeout(() => { setToast(false) }, 3000); + const newData = [...bookmark_List, item] localStorage.setItem('bookmark', JSON.stringify(newData)); setBookmark_List(newData); } else if (bookmark === false) { + + setToastContent('상품이 북마크에서 제거되었습니다.'); + setTimeout(() => { setToast(false) }, 3000); const newData = bookmark_List.filter((bookmarkItem) => {return bookmarkItem.id !== item.id}); @@ -88,17 +105,21 @@ function Item ({ item, bookmark_List, setBookmark_List }) { } }, [bookmark]) - // 북마크 리스트에서 북마크 해제했을 때 (상품 리스트 연동 해제) + // 북마크 리스트에서 북마크 해제했을 때 (상품 리스트에도 연동) useEffect(() => { (check === undefined) && setBookmark(false)}, [bookmark_List]) return ( <> - {(modal) && } + {(modal) && + } {(item.type === 'Product') && ( // product type -
+ { event.stopPropagation(); @@ -108,32 +129,32 @@ function Item ({ item, bookmark_List, setBookmark_List }) { {(item.discountPercentage !== null) && `${item.discountPercentage}%`} {parseInt(item.price).toLocaleString()}원 -
+ )} {(item.type === 'Category') && ( // Category type -
+ { event.stopPropagation(); bookmarkButtonClick()}} bookmark={bookmark}>★ # {item.title} -
+ )} {(item.type === 'Exhibition') && ( // Exhibition type -
+ { event.stopPropagation(); bookmarkButtonClick()}} bookmark={bookmark}>★ {item.title} {item.sub_title} -
+ )} {(item.type === 'Brand') && ( // Brand type -
+ { event.stopPropagation(); @@ -143,7 +164,7 @@ function Item ({ item, bookmark_List, setBookmark_List }) { 관심고객수 {parseInt(item.follower).toLocaleString()} -
+ )} ) diff --git a/coz-shopping/src/Component/ItemFilter.js b/src/Component/ItemFilter.js similarity index 100% rename from coz-shopping/src/Component/ItemFilter.js rename to src/Component/ItemFilter.js diff --git a/coz-shopping/src/Component/MainComponent/BookmarkList.js b/src/Component/MainComponent/BookmarkList.js similarity index 98% rename from coz-shopping/src/Component/MainComponent/BookmarkList.js rename to src/Component/MainComponent/BookmarkList.js index 7fe874865..9790be842 100644 --- a/coz-shopping/src/Component/MainComponent/BookmarkList.js +++ b/src/Component/MainComponent/BookmarkList.js @@ -24,7 +24,6 @@ const ItemBox = styled.div` flex-direction: row; justify-content: center; flex-wrap: wrap; - gap: 95px; ` @@ -41,6 +40,7 @@ const Emptybox = styled.div` border: 1px solid gray; width: 100%; margin: 10px; + margin-bottom: 20px; margin-left: 45px; margin-right: 45px; diff --git a/coz-shopping/src/Component/MainComponent/Footer.js b/src/Component/MainComponent/Footer.js similarity index 95% rename from coz-shopping/src/Component/MainComponent/Footer.js rename to src/Component/MainComponent/Footer.js index e04cacac3..d978ab8db 100644 --- a/coz-shopping/src/Component/MainComponent/Footer.js +++ b/src/Component/MainComponent/Footer.js @@ -4,6 +4,7 @@ const Container = styled.div` height: 100%; display: flex; flex-direction: column; + border-top: 0.1px solid gray; color: gray; ` diff --git a/coz-shopping/src/Component/MainComponent/Header.js b/src/Component/MainComponent/Header.js similarity index 93% rename from coz-shopping/src/Component/MainComponent/Header.js rename to src/Component/MainComponent/Header.js index fe4abf05a..8bbcc1a69 100644 --- a/coz-shopping/src/Component/MainComponent/Header.js +++ b/src/Component/MainComponent/Header.js @@ -6,6 +6,8 @@ import LogoImg from '../../img/logo.jpg' const Container = styled.nav` height: 100%; + border-bottom: 1px solid rgba(184, 184, 184, 0.89); + box-shadow: 0px 2px 15px rgba(184, 184, 184, 0.89); display: flex; flex-direction: row; diff --git a/coz-shopping/src/Component/MainComponent/ItemList.js b/src/Component/MainComponent/ItemList.js similarity index 57% rename from coz-shopping/src/Component/MainComponent/ItemList.js rename to src/Component/MainComponent/ItemList.js index a3fc2e96f..7f6576425 100644 --- a/coz-shopping/src/Component/MainComponent/ItemList.js +++ b/src/Component/MainComponent/ItemList.js @@ -23,18 +23,21 @@ const ItemBox = styled.div` flex-direction: row; justify-content: center; flex-wrap: wrap; - gap: 95px; + /* gap: 95px; */ - margin-top: 10px; + /* margin-top: 10px; */ ` -function ItemList ({ items, bookmark_List, setBookmark_List }) { // 1) MainPage가 마운트 될 때 서버에서 받아온 데이터 2) 북마크 관련 전역 상태 +function ItemList ({ items, bookmark_List, setBookmark_List, setToast, setToastContent }) { // 1) MainPage가 마운트 될 때 서버에서 받아온 데이터 2) 북마크 관련 전역 상태 3) 토스트 ui 관련 상태 return ( 상품 리스트 {items.map((item) => { - return + return })} diff --git a/coz-shopping/src/Component/MainComponent/Menu.js b/src/Component/MainComponent/Menu.js similarity index 64% rename from coz-shopping/src/Component/MainComponent/Menu.js rename to src/Component/MainComponent/Menu.js index 32e0b1349..087406463 100644 --- a/coz-shopping/src/Component/MainComponent/Menu.js +++ b/src/Component/MainComponent/Menu.js @@ -1,5 +1,6 @@ import { styled } from "styled-components"; import { Link } from "react-router-dom"; +import itemImg from '../../img/item.png' const Container = styled.div` position: relative; @@ -13,22 +14,21 @@ const Arrow = styled.div` right: 15%; border-left: 30px solid transparent; border-right: 30px solid transparent; - border-bottom: 30px solid blue; + border-bottom: 30px solid white; ` -// 🔴 해당부분 리뷰 부탁드립니다 (z-index 값을 주어서 해당 태그가 가장 위로 올라오도록 설정했는데, Item 컴포넌트의 이미지에 가려져서 최상단에 위치히지 않습니다. 무슨 문제일까요?) const Box = styled.div` display: flex; flex-direction: column; position: absolute; - /* z-index: 200; */ - transform: translate(-80px, 20px); - width: 150px; + transform: translate(-110px, 20px); + width: 180px; height: 140px; - background-color: blue; + background-color: white; + box-shadow: 4px 4px 10px rgba(184, 184, 184, 0.89);; border-radius: 10%; - color: white; + color: black; ` const Content = styled.div` @@ -48,8 +48,13 @@ const Content = styled.div` } & .Link { - color: white; + color: black; text-decoration: none; + + & img { + width: 15px; + height: auto; + } } ` @@ -60,10 +65,10 @@ function Menu () { OOO님, 안녕하세요! - 상품리스트 페이지 + 상품리스트 페이지 - 북마크 페이지 + ☆ 북마크 페이지 diff --git a/coz-shopping/src/Component/Modal.js b/src/Component/Modal.js similarity index 74% rename from coz-shopping/src/Component/Modal.js rename to src/Component/Modal.js index e4d123402..8b1cfcc08 100644 --- a/coz-shopping/src/Component/Modal.js +++ b/src/Component/Modal.js @@ -1,4 +1,5 @@ import { styled } from "styled-components"; +import { useEffect } from "react"; const Background = styled.div` position: fixed; @@ -66,16 +67,30 @@ const Title = styled.div` font-size: 1.5rem; ` +function Modal ({ item, setModal, bookmark, setBookmark, setToast, setToastContent }) { + const bookmarkButtonClick = () => { + setBookmark(!bookmark) + setToast(true)} + + useEffect(() => { + + if(bookmark === true){ + setToastContent('상품이 북마크에 추가되었습니다.'); + setTimeout(() => { setToast(false) }, 3000); + } else { + setToastContent('상품이 북마크에서 제거되었습니다.'); + setTimeout(() => { setToast(false) }, 3000); + } + }, [bookmark]) -function Modal ({ item, setModal, bookmark, setBookmark }) { return ( {setModal(false)}}> {setModal(false)}}>✕ - {setBookmark(!bookmark)}} >★ + {(item.type === 'Category') && '# '}{(item.type === 'Brand') ? item.brand_name : item.title} diff --git a/src/Component/Toast.js b/src/Component/Toast.js new file mode 100644 index 000000000..417ae3b1c --- /dev/null +++ b/src/Component/Toast.js @@ -0,0 +1,55 @@ +import { styled } from "styled-components"; +import { useEffect } from "react"; + +const Container = styled.div` + position: absolute; + z-index: 999; + transform: translate(145px,900px); + display: none; + + &.notification { + display: block; + transition: transform 2s ease-in-out; + animation: toast-in-right 2s; + } + + @keyframes toast-in-right { + from { + transform: translate(1450px,700px); + } + to { + transform: translate(1080px,700px); + } + } +` + +const Message = styled.div` + position: relative; + padding: 14px; + border: 1px solid black; + border-radius: 0.8rem; + box-shadow: 1px 1px 8px rgba(184, 184, 184, 0.89); + + background-color: white; + color: black; + font-weight: bolder; + font-size: 1.2rem; +` + +const BookmarkButton = styled.span` + color: ${(props) => (props.toastContent==='상품이 북마크에서 제거되었습니다.') ? '#DFDFDF;' : '#FFD361;'}; +` + + +function Toast ({ toast, toastContent }) { + + return ( + + + {toastContent} + + + ) +} + +export default Toast; \ No newline at end of file diff --git a/coz-shopping/src/Page/BookmarkListPage.js b/src/Page/BookmarkListPage.js similarity index 91% rename from coz-shopping/src/Page/BookmarkListPage.js rename to src/Page/BookmarkListPage.js index 25236f563..99f7dcccd 100644 --- a/coz-shopping/src/Page/BookmarkListPage.js +++ b/src/Page/BookmarkListPage.js @@ -4,24 +4,23 @@ import Header from "../Component/MainComponent/Header"; import Footer from "../Component/MainComponent/Footer"; import ItemFilter from "../Component/ItemFilter"; import BookmarkItem from "../Component/BookmarkItem"; +import Toast from "../Component/Toast"; const Container = styled.div` width: 100vw; height: 100vh; - + display: flex; flex-direction: column; ` const HeaderBox = styled.header` flex: 1 0 0; - - border-bottom: 1px solid black; ` const FooterBox = styled.div` - flex: 1 0 0; + flex: 0.7 0 0; ` const Main = styled.main` @@ -39,9 +38,6 @@ const ItemBox = styled.div` flex-direction: row; justify-content: center; flex-wrap: wrap; - gap: 95px; - - margin-top: 10px; ` function BookmarkListPage ({ @@ -51,6 +47,9 @@ function BookmarkListPage ({ const [filter, setFilter] = useState(''); const [index, setIndex] = useState(0); // 화면에 표시할 아이템 개수 관련 상태 + const [toast, setToast] = useState(false); // toast 메세지 띄울지 여부 + const [toastContent, setToastContent] = useState(''); // toast에 들어가는 문구 + useEffect(() => {setIndex(8)}, []) // 화면에 표시할 아이템 개수 useEffect(() => {setIndex(8)}, [filter]) // filter 변경 -> index 초기화 @@ -122,13 +121,14 @@ function BookmarkListPage ({ bookmarkItem={item} // 1) 렌더링 할 개별 아이템 bookmark_List={bookmark_List} setBookmark_List={setBookmark_List} // 2) 북마크 관련 전역 상태 -> 북마크 등록/삭제 연관 all_bookmark={all_bookmark} index={index} filter={filter} - />) + setToast={setToast} setToastContent={setToastContent}/>) })}
+ ) } diff --git a/coz-shopping/src/Page/ItemListPage.js b/src/Page/ItemListPage.js similarity index 84% rename from coz-shopping/src/Page/ItemListPage.js rename to src/Page/ItemListPage.js index fad204159..dae007645 100644 --- a/coz-shopping/src/Page/ItemListPage.js +++ b/src/Page/ItemListPage.js @@ -4,6 +4,7 @@ import Header from "../Component/MainComponent/Header"; import Footer from "../Component/MainComponent/Footer"; import ItemFilter from "../Component/ItemFilter"; import Item from "../Component/Item"; +import Toast from "../Component/Toast"; const Container = styled.div` @@ -16,12 +17,10 @@ const Container = styled.div` const HeaderBox = styled.header` flex: 1 0 0; - - border-bottom: 1px solid black; ` const FooterBox = styled.header` - flex: 1 0 0; + flex: 0.7 0 0; ` const Main = styled.main` @@ -39,16 +38,18 @@ const ItemBox = styled.div` flex-direction: row; justify-content: center; flex-wrap: wrap; - gap: 95px; - margin-top: 10px; + /* gap: 95px; */ ` + function ItemListPage ({ bookmark_List, setBookmark_List }) { const [items, setItems] = useState([]); // 서버에서 받아오는 상품 데이터 const [filter, setFilter] = useState(''); const [index, setIndex] = useState(0); // 화면에 표시할 아이템 개수 관련 상태 + const [toast, setToast] = useState(false); // toast 메세지 띄울지 여부 + const [toastContent, setToastContent] = useState(''); // toast에 들어가는 문구 const all_Items = JSON.parse(localStorage.getItem('all_Items')); // 로컬에 저장한 상품 데이터 @@ -57,8 +58,6 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { useEffect(() => { // index 혹은 filter 변경 -> 화면에 렌더링 되는 아이템 변화 (scroll 움직임과 연동) - - console.log(index); const request = async () => { try { @@ -89,15 +88,15 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { localStorage.setItem('all_Items', JSON.stringify(data));} } catch (error) { - console.log('Response error', error); + console.log('Response error', error)} } - } request(); if(filter === '' || filter === 'all'){ const renderingItems = all_Items.filter((item, idx) => (index-8 <= idx && idx < index)) setItems(renderingItems); + } else { const filtered = all_Items.filter((item) => item.type === filter); const filtered_data = filtered.filter((item, idx) => (index-8 <= idx && idx < index)); @@ -109,28 +108,25 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { // 무한 스크롤 -> 레퍼런스 참고해서 구현함 => 이를 활용해서 데이터 올바르게 처리할 로직 구현해야 함 (https://abangpa1ace.tistory.com/118) 참고 const handleScroll =() => { - console.log('스크롤 이벤트 발생 중') - const { scrollHeight, scrollTop, clientHeight } = document.documentElement; - if(scrollTop === 0){ - (0 < index-8) && setIndex(index-8); - window.scrollTo(0,15)} + if(scrollTop === 0 && 0 < index-8){ + setIndex(index-8); + window.scrollTo(0,1)} if (scrollTop + clientHeight >= scrollHeight) { - if(items.length === 0 || document.documentElement.scrollHeight <= document.documentElement.clientHeight){ // 더 이상 렌더링할 아이템이 없을 경우 -> index를 증가시키지 않음 setIndex(index-8); } else { setIndex(index+8); } - window.scrollTo(0, scrollTop-15)} + + window.scrollTo(0, scrollTop-1)} } useEffect(() => { window.addEventListener('scroll', handleScroll); - return () => window.removeEventListener('scroll', handleScroll); - }, [handleScroll]) + return () => window.removeEventListener('scroll', handleScroll)}, [handleScroll]) return ( @@ -142,13 +138,17 @@ function ItemListPage ({ bookmark_List, setBookmark_List }) { {items.map((item) => { - return + return })}