diff --git a/src/pages/answer/AnswerContainer.js b/src/pages/answer/AnswerContainer.js
index c8faf50..9644c18 100644
--- a/src/pages/answer/AnswerContainer.js
+++ b/src/pages/answer/AnswerContainer.js
@@ -2,12 +2,12 @@ import { useState, useEffect, useContext } from 'react';
import ReactPlayer from 'react-player';
-import { useNavigate } from 'react-router-dom';
-
+import { useNavigate, useParams } from 'react-router-dom';
+import useIntersect from 'hooks/useIntersect';
import { getSubjectsOnQuestions, getSubject } from '../../api/api.subjects.js';
import { deleteQuestion, createAnswer } from '../../api/api.questions';
import { updateAnswersPartial } from '../../api/api.answers';
-
+import FeedSkeleton from 'components/feed/FeedSkeleton';
import PopOverMenu from 'components/modal/PopOverMenu';
import * as S from '../post/PostStyle';
import * as Layout from 'components/answerFeedCard/FeedCardLayout';
@@ -21,41 +21,97 @@ import { pathState } from 'components/common/pathState.js';
import { PagePath } from 'context/PathContext.js';
import handleExtractVideoId from 'utils/ExtractYoutubeId.js';
+const DEFAULT_LIMIT = 0;
+const DEFAULT_OFFSET = 0;
export default function Answer() {
+ const [questionCount, setQuestionCount] = useState(0);
const [questionList, setQuestionList] = useState([]);
- const [answererProfile, setAnswererProfile] = useState({});
const [isOn, setIsOn] = useState(true);
const [isMenuOpen, setMenuOpen] = useState(false);
const [menuSelected, setMenuSelected] = useState(false);
const [isCopied, setIsCopied] = useState(false);
+
+ const [pageLimit, setPageLimit] = useState(DEFAULT_LIMIT);
+ const [pageOffset, setPageOffset] = useState(DEFAULT_OFFSET);
+ const [hasNext, setHasNext] = useState(false);
+ const [isLoading, setIsLoading] = useState(true);
+
const LocalId = window.localStorage.getItem('id');
const YOUTUBE_BASE = 'https://www.youtube.com/watch?v=';
+ const target = useIntersect(handleIntersection, hasNext);
+ const isEmptyQuestions = questionCount === 0;
const { setIsPath, setSelectUserId, userTitleData } = useContext(PagePath);
const navigate = useNavigate();
- const handleRenderSubjectsOnQ = async (id) => {
+ async function handleIntersection(entry) {
+ if (!target.current || isLoading) return;
+
try {
- const { results } = await getSubjectsOnQuestions(id);
- setQuestionList(results);
+ setIsLoading(true);
+ const res = await getSubjectsOnQuestions(LocalId, pageLimit, pageOffset);
+ const { next, previous, results } = res;
+
+ if (previous === null) {
+ return; // 초기 렌더링 콜백함수 호출될때 중복으로 데이터 불러오지 않기
+ }
+ console.log(isLoading); // 삭제예정
+ setQuestionList((prev) => [...prev, ...results]);
+
+ if (next === null) {
+ setHasNext(false);
+ return;
+ }
+
+ /**
+ * next가 null이 아닐때만 수행하기
+ * next 값이 있을때는 next를 기준으로 offset이 결정되지만,
+ * 더이상 받을 데이터가 없을때는 (=next가 null일때) offset을 마지막 offset으로 유지(업데이트x)
+ * 다시 post 진입하면 처음 상태(offset = 0)
+ */
+
+ const nextSearchParams = new URLSearchParams(new URL(next).search);
+ setPageOffset(nextSearchParams.get('offset'));
} catch (error) {
console.log(error);
+ } finally {
+ setIsLoading(false);
}
- };
+ }
- /* const handleRenderSubjectProfile = async (id) => {
+ const handleLoaded = async (LocalId) => {
try {
- const result = await getSubject(id);
- const { name, imageSource } = result;
+ const res = await getSubjectsOnQuestions(LocalId, pageLimit, pageOffset);
+ const { count, next, results } = res;
+ console.log(hasNext);
+ setQuestionCount(count);
+ setQuestionList(results);
+
+ if (!next) return;
- setAnswererProfile({ ...answererProfile, name, imageSource });
+ // 처음 보여지는 page 외 추가 page가 있는 경우 실행
+ const nextSearchParams = new URLSearchParams(new URL(next).search);
+
+ setHasNext(true);
+ setPageLimit(nextSearchParams.get('limit'));
+ setPageOffset(nextSearchParams.get('offset'));
} catch (error) {
console.log(error);
+ } finally {
+ setIsLoading(false);
}
- }; */
-
+ };
+ // const handleRenderSubjectsOnQ = async (id) => {
+ // try {
+ // const { results } = await getSubjectsOnQuestions(id);
+ // setQuestionList(results);
+ // } catch (error) {
+ // console.log(error);
+ // }
+ // };
+ console.log(hasNext);
const handleAllDeleteQuestionList = async (id) => {
try {
const { results } = await getSubjectsOnQuestions(id);
@@ -67,6 +123,7 @@ export default function Answer() {
});
setQuestionList([]);
+ setQuestionCount(0);
} catch (error) {
console.log(error);
}
@@ -147,8 +204,7 @@ export default function Answer() {
useEffect(() => {
setSelectUserId(LocalId);
- handleRenderSubjectsOnQ(LocalId);
- /* handleRenderSubjectProfile(LocalId); */
+ handleLoaded(LocalId);
if (pathState()) {
setIsPath(true);
} else {
@@ -169,10 +225,10 @@ export default function Answer() {
- {questionList ? `${questionList.length}개의 질문이 있습니다` : `아직 질문이 없습니다`}
+ {questionList ? `${questionCount}개의 질문이 있습니다` : `아직 질문이 없습니다`}
- {!questionList ? (
+ {!isLoading && isEmptyQuestions ? (
) : (
<>
@@ -181,74 +237,74 @@ export default function Answer() {
const isSelected = question?.id == menuSelected;
const isRejected = question?.answer?.isRejected === true;
-
-
const key = handleExtractVideoId(question?.answer?.content);
const youtubeURL = YOUTUBE_BASE + key;
-
return (
-
- {isMenuOpen && isSelected && (
-
+
+ {isMenuOpen && isSelected && (
+
+ )}
+
+
- )}
-
-
-
-
-
-
-
-
- {question?.answer ? (
- <>
-
- 답변 완료
- {!isRejected ? (
-
- {question.answer.content}
-
- {question.answer.content.includes(YOUTUBE_BASE) && (
-
- )}
-
- ) : (
- 답변 거절
- )}
- >
- ) : (
- <>
- 미답변
-
- >
- )}
-
-
-
-
-
+
+
+
+
+
+
+ {question?.answer ? (
+ <>
+
+ 답변 완료
+ {!isRejected ? (
+
+ {question.answer.content}
+
+ {question.answer.content.includes(YOUTUBE_BASE) && (
+
+ )}
+
+ ) : (
+ 답변 거절
+ )}
+ >
+ ) : (
+ <>
+ 미답변
+
+ >
+ )}
+
+
+
+
+
+ {isLoading && }
+ >
);
})}
>
@@ -257,6 +313,7 @@ export default function Answer() {
{isCopied && }
+
>
);
}
diff --git a/src/pages/post/PostStyle.js b/src/pages/post/PostStyle.js
index df57574..fe8f9d9 100644
--- a/src/pages/post/PostStyle.js
+++ b/src/pages/post/PostStyle.js
@@ -118,5 +118,6 @@ export const CreateQuestionButton = styled.button`
`;
export const Target = styled.div`
- height: 1px;
+ width: 100%;
+ height: 50px;
`;