묻고 답해요
156만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결
리엑트 무한스크롤기능 ㅠㅠ 5일째 안되고있어요...
useQuery를 이용해서, apple검색api를 활용한 페이지를 만들고있는데요.apple검색api에는 'page, offset'이라는 옵션이 없어요ㅠㅠ그래서 slice해서 하고있는데ㅠㅠ분명 로그는 나오는데 observerTarget의 height값을 아무리 크게 100, 500px이렇게 해도 무한스크롤기능이 안돼는데ㅠㅠ...정말 5일째 이것만 붙잡고 끙끙앓고있어요 아무리 로그찍어도 왜 안되는질 모르겠어요ㅠ...도와주세요ㅠㅠ... List컴포넌트는import React, {useEffect, useState, useRef} from 'react' import Header from './inc/Header' import Star from './Star' import {useLocation} from 'react-router-dom' import { useQuery } from '@tanstack/react-query' import { fetchSearchWord } from '../api/searchApi' const List = () => { // 로딩상태 const [isLoading, setIsLoading] = useState(true); const location = useLocation() const dataFromState = location.state?.data // search컴포넌트에서 전달받은 데이터 // 만약state에 데이터가 없다면, 캐시에서 데이터를 가져오기 위해 useQuery사용 const {data: cacheData} = useQuery( { queryKey: ['resultSearchWord', location.state?.data?.searchQuery], // 캐시된 데이터를 위한 key(location.state.data객체의 속성 중 하나가 searchQuery임) queryFn: async() => { if(!dataFromState) { // state에 데이터가 없으면 캐시에서 데이터를 불러옴 const result = await fetchSearchWord(location.state?.data?.searchQuery) return result } return dataFromState }, enabled: !!location.state?.data // 데이터가 있을때만 쿼리실행 } ) const initialData = dataFromState || cacheData // state에서 데이터가 없으면 캐시된 데이터를 사용 // INF[s] const observerRef = useRef() const [displayData, setDisplayData] = useState([]) const [currentPage, setCurrentPage] = useState(1) useEffect(() => { console.log('currentPage:', currentPage); if (initialData) { const newData = initialData.slice(0, currentPage * 10); console.log('newData:', newData); setDisplayData(newData); // 새 데이터를 덮어쓰는 방식 } }, [initialData, currentPage]); // console.log(`displayData = ${JSON.stringify(displayData)}`); useEffect(() => { if (!initialData || initialData.length === 0) { console.log('observerRef.current is null'); return; } const observer = new IntersectionObserver( (entries) => { console.log('Observer entries:', entries); // 스크롤 이벤트가 발생하는지 확인 if (entries[0]?.isIntersecting) { console.log('Target is intersecting'); setCurrentPage((prev) => { const nextPage = prev + 1; console.log('nextPage:', nextPage); // nextPage 값을 확인 if (nextPage > Math.ceil(initialData.length / 10)) { console.log('모든 데이터가 로드되었습니다.'); return prev; // 모든 데이터가 로드되었을 때는 현재 페이지 유지 } return nextPage; // 새로운 페이지로 증가 }); } }, { threshold: 0, // 더 민감하게 설정 rootMargin: '100px', // 더 넓게 감지 } ); if (observerRef.current) { observer.observe(observerRef.current); } return () => observer.disconnect(); }, [initialData, observerRef]); // INF[e] useEffect(()=> { setIsLoading(true) // 검색 결과 로딩이 끝난 후 로딩 상태를 false로 변경 const timer = setTimeout(() => { setIsLoading(false) }, 500) // 임의의 딜레이(0.5초)를 추가해 로딩 표시 return () => clearTimeout(timer) // 컴포넌트 언마운트 시 타이머 정리 }, [initialData]) if(!initialData) { return <p>No data found. Please perform a search first.</p> } if(isLoading) { return <div id="container"> <div className="stick"></div> <div className="stick"></div> <div className="stick"></div> <div className="stick"></div> <div className="stick"></div> <div className="stick"></div> <h1 className="tit-Loadng">Loading...</h1> </div> } // console.log(`displayData = ${JSON.stringify(displayData)}`); // console.log('initialData:', initialData); return ( <> <Header></Header> <div className='box-wrap'> {displayData.length === 0 && <p>Loading more items...</p>} { displayData.map((item, idx) => { const sliceImg = item.screenshotUrls.slice(0,3) // 0번째부터 2번째까지(원본배열 안건드림) return <div className='box' key={idx}> <div className='top'> <div className='left'> <img src={item.artworkUrl60} alt={item.trackName}/> <div className='center'> <span className='title'>{item.trackName}</span> {/* <span className='subtext'>{item.shortDescription}</span> */} <span className='genre'>{item.primaryGenreName}</span> </div> </div> <div className='right'><button type='button'>받기</button></div> </div> <div className='middle'><Star item={item}></Star></div> <div className='bottom'> <ul className='imgbox'> { sliceImg.map((value, idx) => { return <li key={idx}><img src={value} alt=""/></li> }) } </ul> </div> </div> }) } <div ref={observerRef} className="observerTarget"></div> </div> </> ) } export default List scss는 @charset "utf-8"; .observerTarget { height: 1px; background-color: red; position: relative; } api기능은 let currentData = []; // 받은 데이터를 저장할 변수 let currentLimit = 10; // 요청할 데이터의 개수 export const fetchSearchWord = async (query, country = 'KR', entity = 'software', media = 'software', limit = currentLimit) => { const response = await axios.get(`https://itunes.apple.com/search`, { params: { term: query, country, entity, media, limit } }); // 받은 데이터를 현재 데이터에 추가 currentData = [...currentData, ...response.data.results]; return response.data.results; }
-
해결됨풀스택 리액트 토이프로젝트 - REST, GraphQL (for FE개발자)
무한스크롤 관련
무한스크롤 구현시 <div ref={fetchMoreEl} /> 이부분이 화면스크롤시 제대로 감지가 안되는 건지 useEffect 에서 intersecting 이 계속 false 더군요 제가 해결한 방법은 <div ref={fetchMoreEl} style={{ border: '1px solid white' }}></div> 이렇게 입력해서 정상작동하는 것을 확인했습니다. 비슷한 문제 발생시 참고용~