[ react ] 댓글목록 무한스크롤

Suji Kang·2023년 11월 16일
1
post-custom-banner

🐾 라이브러리 여러가지가 있지만 그중에 오늘 사용할것은❓

🔎 react-intersection-observer
특정 컴포넌트(요소태그),viewport안에 발견되었을때 스크롤된다.

npm install react-intersection-observer --save


빨간색 밑부분에 div tag를 넣어준다.

  • 앞에있는 ref 는 우리가 관찰할 요소를 알려주는데 사용
  • 뒤에있는 useInView 는 관찰할 요소가 화면에 나타나면 true, 사라지면 false를 반환하는 변수
import { useInView } from 'react-intersection-observer'

	// 앞에있는 ref 는 우리가 관찰할 요소를 알려주는데 사용
    // 뒤에있는 useInView 는 관찰할 요소가 화면에 나타나면 true, 사라지면 false를 반환하는 변수 
    const [ref, inView] = useInView(); // useInView() 는 true or false 를 반환한다.

    useEffect(() => {
        console.log('inView', inView);
    }, [inView]);

return(
		<div
           ref={ref}
           style={{
                backgroundColor: 'red',
                 }}>
       </div>
  );

const [currentPage, setCurrentPage] = useState(1);
    // 앞에있는 ref 는 우리가 관찰할 요소를 알려주는데 사용
    // 뒤에있는 useInView 는 관찰할 요소가 화면에 나타나면 true, 사라지면 false를 반환하는 변수 
    const [ref, inView] = useInView(); // useInView() 는 true or false 를 반환한다.

    useEffect(() => {
        let tmp = async () => {
            if (accessToken === null) return;
            if (inView === false) return;
            try {
                let res = await axios.get(`/api/comments?activityId=${props.activityId}&limit=${3}&page=${currentPage}`, // 3개씩 가져오기 
                    {
                        headers: { Authorization: `Bearer ${accessToken}` }
                    })
                setCurrentPage(currentPage + 1);
                setCommentList([...commentList, ...res.data]); // 기존 댓글(commentList)과, 새로운 댓글을 추가해준다.
            } catch (err) {
                alert('댓글목록 오류');
            }
        }
        tmp();
    }, [props.activityId, accessToken, inView]);


inView가 true 일때(빨간부분에 도달하면),

app.get('/api/comments', async (req, res) => {
    const activityId = Number(req.query.activityId);
    const limit = Number(req.query.limit); //한페이지에 보여줄 댓글 갯수
    const page = Number(req.query.page); //보여줄 페이지
    const offset = (page - 1) * limit; //건너뛸 댓글 갯수
    let sql = `
        select * from tbl_comments
        where activity_id = ?
        order by created_date asc
        limit ? offset ?;
   `;

    try {
        const token = req.headers.authorization.replace('Bearer ', '');
        let user = jwt.verify(token, process.env.JWT_SECRET);
        let [results] = await pool.query(sql, [activityId, limit, offset])

        results = results.map((el) => ({ ...el, owner: el.writer_email === user.email })); //객체를 만드는 중괄호

        console.log(results);
        res.json(results);

    } catch (err) {
        res.status(500).json('오류발생');
    }
})

그런데 여기서 문제❗️
처음에 댓글이 3개 보이는데, 거기서 댓글을 '마지막댓글'을 추가하면,
...commentList, ...res.data]기존에 있는거에, 마지막에 추가한걸 추가하라고했는데,
근데 데이터 베이스는 댓글이 더 있잖아❓
그래서 '마지막댓글이' 처음에 댓글이 3개 보인후, 그바로뒤에도 있고,
또 원래있던 데이터 베이스는 댓글 맨뒤에도 또 '마지막댓글'이 출력되어서
2개의 '마지막댓글'이 있다. 사이에 끼어서 들어간다.

그래서❗️댓글목록을 끝까지 다 가져온 상태라면 직접 화면에도 보이게 추가해준다.

   const [isEnd, setIsEnd] = useState(false); // 댓글을 끝까지 다 가져왔다면 true 아니면 false

 useEffect(() => {
        let tmp = async () => {
            if (accessToken === null) return;
            if (inView === false) return;
            if (isEnd === true) return; //🌟추가코드
            try {
                let res = await axios.get(`/api/comments?activityId=${props.activityId}&limit=${3}&page=${currentPage}`, // 3개씩 가져오기 
                    {
                        headers: { Authorization: `Bearer ${accessToken}` }
                    })
                setCurrentPage(currentPage + 1);
                //댓글목록을 끝까지 다 가져온 상태라면 직접 화면에도 보이게 추가해준다.
                if (res.data.length === 0) {//🌟추가코드
                    setIsEnd(true);
                    return;
                }
                setCommentList([...commentList, ...res.data]); // 기존 댓글(commentList)과, 새로운 댓글을 추가해준다.
            } catch (err) {
                alert('댓글목록 오류');
            }
        }
        tmp();
    }, [props.activityId, accessToken, inView]);

  const onCommentClick = async () => {
        try {
            let res = await axios.post('/api/comments', {
                content,
                activityId: props.activityId
            },
                {
                    headers: { Authorization: `Bearer ${accessToken}` }
                }
            );
            if (isEnd === true) { //🌟추가코드
                setCommentList([...commentList, res.data]); // 기존 댓글(commentList)과, 새로운 댓글을 추가해준다.
            }
            alert('댓글작성 성공!');
            setContent('');
        } catch (err) {
            alert('댓글작성 오류');
        }
    }; //body에다가 content를 담아서 express로 보내준다.
profile
나를위한 노트필기 📒🔎📝
post-custom-banner

0개의 댓글