React 댓글 목록 무한 스크롤

alert("april");·2023년 11월 29일
0

React

목록 보기
17/17
post-custom-banner

댓글이 만약 1만개라면...? 아니면 이미지가 포함된 댓글이라면?
한번에 가져올때 로딩이 걸리거나 속도가 느려질게 뻔하다

라이브러리 사용

react intersection-observer

특정 컴포넌트(요소,태그) viewport 안에 발견되어있는지를 감지하는 라이브러리
(이외에도 react window, react infinite scroll 등 여러가지가 있다)

1. 설치

npm install react-intersection-observer --save

2. 관찰대상 알려주기(빨간 div)

activityCommentSection.js

import {useInView} from "react-intersection-observer";

const ActivityCommentSection = (props)=>{
.
.
.
    // 앞에있는 ref는 우리가 관찰할 요소를 알려주는데 사용
    // 뒤에있는 inView는 우리가 관찰할 요소가 화면에 나타나면 true
    // 안나타나면 false가 들어있는 변수
    const [ref, inView] = useInView();

     <CommentListWrap>
                {
                    commentList.map((comment)=> <CommentBlock
                        key={comment.id} 
                        onDeleteClick={onDeleteClick} 
                        comment={comment}
                        />)
                }
                <div ref={ref} style={{backgroundColor:'red'}}>ddd</div>
     </CommentListWrap>

3. 몇개씩 가져올껀지, 무슨 페이지를 가져올껀지 수량 알려주기

activityCommentSection.js(State 변수 만들기)

const [currentPage, setCurrentPage] = useState(1);
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}`, {
                    headers:{Authorization:`Bearer ${accessToken}`}
                })
                setCurrentPage(currentPage + 1); // 2페이지로 바꿔놓고
                if(res.data.length === 0){
                    setIsEnd(true);
                }
                setCommentList([...commentList, ...res.data]); // 기존에 3개가 있었으면 +3개를 추가해서 배열로 붙여줘야 함
            }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] )
            }
            alert('댓글 추가 성공!!');
            
        }catch(err){
            alert('댓글 추가 중 오류 발생..!');
        }
    }

app.js

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])    
.
.
.

    }catch(err){
        res.status(500).json('오류발생');
    }
})
profile
Slowly but surely
post-custom-banner

0개의 댓글