현석님의 말씀을 듣고 jsx를 리턴하기 전에 로딩중임을 판단하여 early return을 해보았다.
- 메인페이지에서 페이지 자체의 return
import React, { useCallback, useEffect } from 'react'; import { useHistory } from 'react-router'; import ZzalList from '@domains/Zzal/ZzalList'; import SearchBar from '@domains/Search'; import useAxios from '@hooks/useAxios'; const DEFAULT_CATEGORY = '61755fa5359c4371f68ac695'; const MainPage = () => { const history = useHistory(); const [zzalList, fetchList] = useAxios(`/posts/channel/${DEFAULT_CATEGORY}`); useEffect(() => { fetchList(); }, []); if (zzalList.isLoading) { return (<div>loading...</div>); } const handleToSearchPage = useCallback(value => { value && history.push(`/search/${value}`); }, []); return ( <> <SearchBar onToSubmitPage={handleToSearchPage}></SearchBar> <ZzalList zzalList={zzalList} ></ZzalList> </> ); }; export default MainPage;
그리고 알 수 없는 결과... 여기는 왜 안되는걸까?
- zzalList에서도 받아온 isLoading에 따라 early return을 줘봤다.
import React, { useState, useRef, useEffect, useCallback } from 'react'; import PropTypes from 'prop-types'; import styled from '@emotion/styled'; import ZzalItem from '@domains/Zzal/ZzalItem'; import Grid from '@base/Grid'; let observer = null; const LOAD_POST_EVENT_TYPE = 'fetch'; const checkIntersect = (entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { observer.unobserve(entry.target); entry.target.dispatchEvent(new CustomEvent(LOAD_POST_EVENT_TYPE)); } }); }; const ZzalList = ({ zzalList }) => { const [itemCount, setItemCount] = useState(6); const [isFetchable, setIsFetchable] = useState(false); const init = useRef(false); const ref = useRef(null); const fetchItem = () => setItemCount(prev => prev + 6); const handleLoadPost = useCallback(() => { fetchItem(); observer.observe(ref.current); }, [zzalList, observer]); useEffect(() => { const { isLoading, value } = zzalList; if (isLoading) { return (<div>loading...</div>); } setIsFetchable(ref.current && !isLoading && value && itemCount < value.length); value?.length < itemCount && ref.current?.removeEventListener(LOAD_POST_EVENT_TYPE, handleLoadPost); }, [zzalList, ref, itemCount]); useEffect(() => { if (!ref.current) { return; } ref.current.addEventListener(LOAD_POST_EVENT_TYPE, handleLoadPost); return () => { ref.current?.removeEventListener(LOAD_POST_EVENT_TYPE, handleLoadPost); }; }, [ref, handleLoadPost]); useEffect(() => { if (!observer) { observer = new IntersectionObserver(checkIntersect, { threshold: 0.5 }); } if (!init.current) { init.current = true; return; } if (isFetchable) { observer.observe(ref.current); } }, [observer, isFetchable]); return ( <StyledList> <Grid gridProps={gridProps}> {(zzalList.value || []) .filter((_, idx) => idx < itemCount) .map(item => ( <ZzalItem key={item._id} id={item._id} src={item.image} height='100%'/> )) } <div ref={ref}></div> </Grid> </StyledList> ); }; const gridProps = { xs: { gap: 8, position: ['center', 'center'] }, sm: { gap: 8, position: ['center', 'center'] }, md: { gap: 8, position: ['center', 'center'] }, lg: { gap: 8, position: ['center', 'center'] }, xl: { gap: 8, position: ['center', 'center'] } }; const StyledList = styled.div` width: 994px; margin: 100px auto; box-sizing: border-box; @media(max-width: 1176px) { width: 746px; } @media(max-width: 768px) { width: 490px; } `; ZzalList.propTypes = { zzalList: PropTypes.object }; export default ZzalList;
여기서 궁금한 것
- <div>loading...</div> 부분이 렌더링 되지 않는 이유
- zzalList의 return 에 조건을 건 것인데 왜 헤더와 검색창까지 렌더링이 안되는 것인지?
(에러는 발생하지 않지만..)
- 이렇게 jsx안에서 로딩 중을 판단하니 에러가 없어졌다.
하지만 짤리스트에 로딩중 페이지가 나오진 않는다 무럴까?
import React, { useCallback, useEffect } from 'react'; import { useHistory } from 'react-router'; import ZzalList from '@domains/Zzal/ZzalList'; import SearchBar from '@domains/Search'; import useAxios from '@hooks/useAxios'; const DEFAULT_CATEGORY = '61755fa5359c4371f68ac695'; const MainPage = () => { const history = useHistory(); const [zzalList, fetchList] = useAxios(`/posts/channel/${DEFAULT_CATEGORY}`); useEffect(() => { fetchList(); }, []); const handleToSearchPage = useCallback(value => { value && history.push(`/search/${value}`); }, []); return ( <> <SearchBar onToSubmitPage={handleToSearchPage}></SearchBar> {zzalList.isLoading ? <h1>loading...</h1> : <ZzalList zzalList={zzalList} ></ZzalList> } </> ); }; export default MainPage;
- 로딩 중 표시를 짤리스트 jsx 안에 넣으니 짤리스트 부분에만 로딩중 표시가 나온다.
import React, { useState, useRef, useEffect, useCallback } from 'react'; import PropTypes from 'prop-types'; import styled from '@emotion/styled'; import ZzalItem from '@domains/Zzal/ZzalItem'; import Grid from '@base/Grid'; let observer = null; const LOAD_POST_EVENT_TYPE = 'fetch'; const checkIntersect = (entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { observer.unobserve(entry.target); entry.target.dispatchEvent(new CustomEvent(LOAD_POST_EVENT_TYPE)); } }); }; const ZzalList = ({ zzalList }) => { const [itemCount, setItemCount] = useState(6); const [isFetchable, setIsFetchable] = useState(false); const init = useRef(false); const ref = useRef(null); const fetchItem = () => setItemCount(prev => prev + 6); const handleLoadPost = useCallback(() => { fetchItem(); observer.observe(ref.current); }, [zzalList, observer]); useEffect(() => { const { isLoading, value } = zzalList; setIsFetchable(ref.current && !isLoading && value && itemCount < value.length); value?.length < itemCount && ref.current?.removeEventListener(LOAD_POST_EVENT_TYPE, handleLoadPost); }, [zzalList, ref, itemCount]); useEffect(() => { if (!ref.current) { return; } ref.current.addEventListener(LOAD_POST_EVENT_TYPE, handleLoadPost); return () => { ref.current?.removeEventListener(LOAD_POST_EVENT_TYPE, handleLoadPost); }; }, [ref, handleLoadPost]); useEffect(() => { if (!observer) { observer = new IntersectionObserver(checkIntersect, { threshold: 0.5 }); } if (!init.current) { init.current = true; return; } if (isFetchable) { observer.observe(ref.current); } }, [observer, isFetchable]); return ( <StyledList> <Grid gridProps={gridProps}> {zzalList.isLoading ? <div>loading...</div> : (zzalList.value || []) .filter((_, idx) => idx < itemCount) .map(item => ( <ZzalItem key={item._id} id={item._id} src={item.image} height='100%'/> )) } <div ref={ref}></div> </Grid> </StyledList> ); }; const gridProps = { xs: { gap: 8, position: ['center', 'center'] }, sm: { gap: 8, position: ['center', 'center'] }, md: { gap: 8, position: ['center', 'center'] }, lg: { gap: 8, position: ['center', 'center'] }, xl: { gap: 8, position: ['center', 'center'] } }; const StyledList = styled.div` width: 994px; margin: 100px auto; box-sizing: border-box; @media(max-width: 1176px) { width: 746px; } @media(max-width: 768px) { width: 490px; } `; ZzalList.propTypes = { zzalList: PropTypes.object }; export default ZzalList;