-
[고양이 사진 검색 사이트] 스크롤 페이지 구현, 랜덤 고양이 배너 section,EventDelegationReact/과제 테스트 2023. 8. 7. 13:59반응형
프로그래머스 과제 테스트 준비
프로그래머스는 html,css, javaScript이기 때문에 실질적으로 도움이 될 만한 React로 준비했다.
테스팅에 목적이 아닌 학습을 위한 구현자료로써, 디자인은 하지 않았고 기능에 초점을 두었다.
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
🐇 스크롤 페이징 구현
유저가 스크롤바 끝가지 이동 시 다음페이지 로딩하도록 만들어야 한다
1. api 호출시 page 추가
export const getSearchCatData = async (keyword, pages) => {return fetchData(`${API_ENDPOINT}/api/cats/search?q=${keyword}&page=${pages}`);};2. 현재 page state로 관리
const [currentPages, setCurrentPages] = useState(1);3. 스크롤 이벤트 함수 구현
// 스크롤 이벤트 처리 함수const handleScroll = () => {// 브라우저의 스크롤 위치와 문서의 전체 높이를 비교하여 끝까지 도달했는지 체크const { scrollTop, clientHeight, scrollHeight } = document.documentElement;if (scrollTop + clientHeight >= scrollHeight - 10) {// 끝까지 도달하면 다음 페이지를 로딩loadMoreCats();}};4. 스크롤시 api 호출
// 스크롤 페이징 구현const loadMoreCats = async () => {if (isLoading) return;setIsLoading(true);try {const response = await getSearchCatData(keyword, currentPages + 1);const newCatsList = response.data;setCatsList([...catsList, ...newCatsList]);setCurrentPages(currentPages + 1);} catch (error) {console.error('Error while loading more cats:', error);} finally {setIsLoading(false);}};5. 페이지 진입시 스크롤 이벤트 리스너 추가
useEffect(() => {// 컴포넌트가 처음 렌더링 될 때 스크롤 이벤트 리스너를 추가window.addEventListener('scroll', handleScroll);return () => {window.removeEventListener('scroll', handleScroll);};}, []);🐇 랜덤고양이 배너 섹션
- 현재 검색 결과 목록 위에 배너형태의 랜덤 고양이 섹션을 추가한다.
- 앱이 구동될 때 /api/cats/random50 api요청 이후 받은 결과를 별도 섹션에 노출
- 겸색결과가 많더라도 화면에 5개만 노출하여 각 이미지는 좌,우 슬라이등 버튼을 가진다
- 좌, 우 버튼을 클릭하면, 현재 노출된 이미지는 사라지고, 이전 또는 다음 이미지를 보여준다. 트랜지션은 선택이다
1. randomCatBanner 컴포넌트 생성
import React, { useEffect, useState } from 'react';import { getRandomCatData } from '../api/api';import styled from 'styled-components';import Loading from './Loading';import SlideShow from './SlideShow';
const BannerContainer = styled.section`display: flex;justify-content: center;align-items: center;padding: 20px;`;
const RandomCatBanner = ({ isDarkMode }) => {const [isLoading, setIsLoading] = useState(true);const [randomCats, setRandomCats] = useState([]);
useEffect(() => {const fetchRandomCats = async () => {try {setIsLoading(true);const response = await getRandomCatData();setRandomCats(response.data);setIsLoading(false);} catch (error) {console.error('Error while fetching random cats:', error);setRandomCats([]);}};
fetchRandomCats();}, []);
if (isLoading) return <Loading isDarkMode={isDarkMode} />;return (<BannerContainer>{randomCats && (<SlideShow catsList={randomCats.slice(0, 5)} isDarkMode={isDarkMode} />)}</BannerContainer>);};
export default RandomCatBanner;2. SlideShow 컴포넌트 생성
import React, { useState } from 'react';import styled from 'styled-components';
const SlideShowContainer = styled.article`display: flex;align-items: center;overflow: hidden;background-color: ${({ isDarkMode }) => (isDarkMode ? 'black' : 'white')};border-radius: 5%;`;
const SlideShowItem = styled.img`width: 200px;height: 200px;margin: 0 5px;transition: transform 0.3s ease-in-out;border-radius: 20%;`;
const SlideShowButton = styled.button`background-color: transparent;border: none;font-size: 20px;cursor: pointer;`;
const SlideShow = ({ catsList, isDarkMode }) => {const [currentIndex, setCurrentIndex] = useState(0);
const handlePrev = () => {setCurrentIndex((prevIndex) =>prevIndex === 0 ? catsList.length - 1 : prevIndex - 1);};
const handleNext = () => {setCurrentIndex((prevIndex) =>prevIndex === catsList.length - 1 ? 0 : prevIndex + 1);};
return (<SlideShowContainer><SlideShowButton onClick={handlePrev}>❮</SlideShowButton><SlideShowItemkey={catsList[currentIndex].id}src={catsList[currentIndex].url}alt={catsList[currentIndex].id}title={catsList[currentIndex].name}loading="lazy"/><SlideShowButton onClick={handleNext}>❯</SlideShowButton></SlideShowContainer>);};
export default SlideShow;🐇 추가 요구사항
🥕 SearchResult에 각 아이템을 클릭하는 이벤트를 EventDelegation을 이용하여 수정
※ 이벤트 위임(Event Delegation)
JavaScript의 대부분 이벤트는 이벤트 흐름(Event Flow)의 이벤트 캡처링, 이벤트 버블링 단계를 거칩니다. 일반적으로 addEventListener() 메서드의 세 번째 매개변수로 true를 전달하지 않은 이상 이벤트 캡처링 단계는 수행되지 않고 이벤트 버블링 단계를 거치는데, 이벤트 버블링은 타겟에서 이벤트가 발생하면 타겟에서 위로 이벤트를 전파하는 것을 말합니다.
1. img click -> container click
<S.ImgContainer onClick={handleItemClick}>{catsList.map((v, i) => (<S.Imgloading="lazy"src={v.url}key={i}alt={v.id}title={v.name}//이전 : onClick={() => displayModal(v.id)} />/>))}</S.ImgContainer>2. img 클릭 이벤트 생성
// Event delegation 함수const handleImgClick = (event) => {const clickedImage = event.target.closest('img');if (clickedImage) {const id = clickedImage.getAttribute('alt');displayModal(id);}};🥕 각 컴포넌트의 내부함수와 Util함수를 잘게 나누기
component / utils 함수 (api) 구별
반응형'React > 과제 테스트' 카테고리의 다른 글
[Input 이벤트] input readonly, 백스페이스 기능 (0) 2023.08.08 [Input 이벤트] 포커스 이벤트, 영역 외부 클릭시 상태 변화, document.addEventListener (0) 2023.08.08 [고양이 사진 검색 사이트] - 이미지 상세 보기 모달 : 모달, keypress, fade in/out (0) 2023.08.07 [고양이 사진 검색 사이트] 검색 페이지 - autofocus, Loading, api 연결, try & catch, async, await,img title (0) 2023.08.07 [고양이 사진 검색 사이트] HTML, CSS - 시맨틱, media query, 다크모드(dark mode) (0) 2023.08.07