반응형
오늘은 캐러셀 컴포넌트에 보일 태그 별 게시글 리스트 데이터 가져오기를 진행했다. 에러 5 종류 이상은 만나 겨우 성공했다. 진짜 온갖 진을 다 뺀 것 같다. 그래도 해결하고 나니 후련하다.
코드를 살펴보기 전에 내가 만들어준 db 구조를 먼저 보자. 데이터 평면화를 위해 다음과 같이 구조를 짰다.
사용자가 선택한 태그 목록 중 현재 캐러셀 컴포넌트에서 보여주고 있는 태그의 인덱스가 키포인트다. 이 값을 useState를 통해 관리해준다. 태그 별 게시글 리스트 저장을 위해 carouselData 라는 이름의 객체 또한 useState를 통해 관리해준다.
posts 컬렉션에 있는 문서들 중 tags 필드의 값인 배열에 해당 tag를 포함하는 문서를 찾아 배열에 넣고, 그 배열을 carouselData 객체에 태그 명의 값으로 저장해준다.
이를 통해 사용자가 선택한 태그에 따른 각각의 게시글 리스트를 캐러셀 컴포넌트를 통해 조회할 수 있다.
import {
doc,
collection,
query,
where,
onSnapshot,
getDoc,
orderBy
} from 'firebase/firestore';
import { db } from '../../firebase';
import CarouselItem from './carouselItem';
import { GreenButton } from '../UI/button';
const Carousel = ({ setPostDetail, tagList, setComp }) => {
const carouselRef = useRef(null);
const [tagIdx, setTagIdx] = useState(0);
const [carouselData, setCarouselData] = useState({});
const fetchPostsByTags = async (selectedTagIdx) => {
try {
const updatedCarouselData = JSON.parse(JSON.stringify(carouselData));
const tagRef = doc(db, 'tags', tagList[selectedTagIdx]);
const tagSnapshot = await getDoc(tagRef);
if (tagSnapshot.exists()) {
const q = query(
collection(db, 'posts'),
where('tags', 'array-contains', tagList[selectedTagIdx]),
orderBy('createdAt', 'desc')
);
const unsubscribe = onSnapshot(q, (snapshot) => {
const tagPosts = [];
snapshot.forEach((d) => {
const postData = d.data();
tagPosts.push({ id: d.id, ...postData });
});
updatedCarouselData[tagList[selectedTagIdx]] = tagPosts;
setCarouselData(updatedCarouselData);
});
return () => unsubscribe();
}
} catch (error) {
console.error('Error fetching posts by tags: ', error);
}
};
useEffect(() => {
fetchPostsByTags(tagIdx);
}, [tagIdx]);
const settings = {
lazyLoad: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
initialSlide: 2,
arrows: true,
beforeChange: (current, next) => {
const carouselElement = carouselRef.current;
if (carouselElement && carouselElement.scrollTo) {
carouselElement.scrollTo({
top: 0,
behavior: 'smooth'
});
}
if (next > current) {
if (tagIdx < tagList.length - 1) setTagIdx((prevIdx) => prevIdx + 1);
else setTagIdx(0);
} else if (next < current) {
if (tagIdx > 0) setTagIdx((prevIdx) => prevIdx - 1);
else setTagIdx(tagList.length - 1);
}
}
};
return (
<>
{tagList.length ? (
<CarouselWrapper>
<TagWrapper>
<p>{`# ${tagList[tagIdx]}`}</p>
<button onClick={() => setComp('tag')}>태그 추가</button>
</TagWrapper>
<Slider ref={carouselRef} {...settings}>
{tagList.map((_, idx) => (
<CarouselItemContainer key={idx}>
{carouselData[tagList[tagIdx]] &&
carouselData[tagList[tagIdx]].map((post, i) => (
<CarouselItem
key={i}
category={tagList[tagIdx]}
title={post.title}
content={post.content}
createdAt={post.createdAt}
idx={i}
setPostDetail={setPostDetail}
/>
))}
</CarouselItemContainer>
))}
</Slider>
</CarouselWrapper>
) : (
<GuideWrapper>
<div>아직 태그를 설정하지 않았어요!</div>
<div>지금 태그를 설정하러 가볼까요?</div>
<GreenButton>태그 설정하러 가기</GreenButton>
</GuideWrapper>
)}
</>
);
};
참고로 timestamp는 다음과 같이 출력해줘야 한다. 직접 출력해주려고 하면 오류가 뜬다. 나도 알고 싶지 않았다^^ 이것 때문에 모니터 부실뻔 '-'
const formattedDate = new window.Date(createdAt.seconds * 1000);
return (
<ItemWrapper
<Date>{formattedDate.toLocaleString()}</Date>
</ItemWrapper>
);
};
참고한 글)
https://stackoverflow.com/questions/30130241/typeerror-date-is-not-a-constructor
반응형
'프로젝트 > 나무(나누고 나눔받는 무한 지식 품앗이)' 카테고리의 다른 글
[React] 텍스트가 넘칠 때 "..." 출력하기 (0) | 2023.07.14 |
---|---|
[React] Link를 통해 props 전달하기 (0) | 2023.07.14 |
[react-query] 리액트 쿼리 개념 및 사용법 간단하게 정리하기(feat. firestore) (0) | 2023.07.06 |
[React&Firebase] react-quill 에디터와 Firebase storage를 사용하여 질문 작성 컴포넌트 구현하기 (0) | 2023.07.05 |
[Error] Cannot destructure property 'basename' of 'react__WEBPACK_IMPORTED_MODULE_0__.useContext(...)' as it is null. (0) | 2023.07.04 |