• 로그인
  • 장바구니에 상품이 없습니다.

home2 게시판 React 게시판 게시글 삭제 -> 게시글 목록에 반영 오류

게시글 삭제 -> 게시글 목록에 반영 오류

2 글 보임 - 1 에서 2 까지 (총 2 중에서)
  • 글쓴이
  • #98759

    쥬니
    참가자
    안녕하세요 게시물 조회하는 코드를 작성중입니다. 이전 문의에서 선생님 덕분에 오류를 잘해결할수있었습니다. 감사합니다!
    현재 코드 구성은 이런식입니다.
    '/'경로에 우선 post.tsx의 post컴포넌트가 있고 그 자식으로 dashboard컴포넌트가 있습니다.
    post: 게시글목록을 조회할수있는 컴포넌트
    dashboard: 게시글 하나하나의 내용을 볼수있는 컴폰넌트
    dashboard 모달창을 띄우고, 해당 컴포넌트 안에서 게시글 삭제를 실행하면 아래의 코드가 실행됩니다.
    const postdelete = async (feedIdToDelete: number) => {
        console.log('삭제할피드', feedIdToDelete);
        //해당피드아이디로 게시물 삭제 api호출
        try {
          const response = await axios.patch(`${API_BASE_URL}/app/feeds/${feedIdToDelete}/delete-status`,
            null,
            {
              headers: {
                'x-access-token': `${token}`,
              },
            }
          );
          console.log(response.data);
          if (response.data.code === 1000) {
            // 3가지 state 모두 전역(recoil)으로 관리중입니다 
            setFeeds([]); //post컴포넌트의 feeds목록을 초기화
            setPage(0); //page를 0으로 설정하여 데이터를 처음부터 새롭게 불러오기   
            setDashboardModified(true); //게시글 수정, 삭제여부를 true로 설정  
            props.onRequestClose(false);
          } else {
            alert('게시글 삭제 불가');
            setPopupIsOpen(false);
            setModalIsOpen(false);
          }
        } catch (error) {
          console.log('게시글 삭제 실패: ', error);
          throw error;
        }
      }
    그리고 아래는 post.tsx입니다.
    import React, { useState, useEffect, useRef } from "react";
    import Modal from 'react-modal';
    import moment from "moment";
    import Slider from "react-slick";
    import { ReactComponent as Bookmark } from '../../assets/bookmark.svg';
    import { ReactComponent as Comment } from '../../assets/comment.svg';
    import { ReactComponent as Heart } from '../../assets/heart.svg';
    import feedloginprofile from "../../images/default_profile.png";
    import PrevArrow from '../../assets/prev-arrow.svg';
    import NextArrow from '../../assets/next-arrow.svg';
    import Dashboard from '../dashboard/Dashboard';
    import styled from "styled-components";
    import { useRecoilState } from 'recoil';
    import { feedsState } from "../../recoil/feedsState";
    import { DashboardModalState, DashboardModifiedState, PageState, PostedState } from "../../recoil/feedModal";
    import axios from "axios";
    export type FeedType = {
      feedId: number;
      feedLoginId: string;
      feedText: string;
      feedCreatedAt: string;
      feedUpdatedAt: string;
      feedCommentCount: number;//TypeScript에서 숫자 데이터 타입: number
      contentsList: {
        contentsId: number;
        contentsUrl: string;//ypeScript에서 배열 데이터 타입 : []
        createdAt: string;
        updatedAt: string;
      }[];
      comments: {
        id: number;
        loginId: string;
        commentText: string;
        createdAt: string;
        updatedAt: string;
      }[];
    }
    export type CommentType = {
      id: number;
      loginId: string;
      commentText: string;
      createdAt: string;
      updatedAt: string;
    }
    function Post() {
      const API_BASE_URL = 'https://api.gridge-test.com';
      const [selectedFeed, setSelectedFeed] = useState<FeedType | null>(null);
      const [dashboardIsOpen, setDashboardIsOpen] = useRecoilState(DashboardModalState);
      const [Posted, setPosted] = useRecoilState(PostedState); // 현재 페이지
      const [DashboardModified, setDashboardModified] = useRecoilState(DashboardModifiedState); // 현재 페이지
      const [feeds, setfeeds] = useRecoilState(feedsState);
      const [page, setPage] = useRecoilState(PageState); // 현재 페이지
      const [loading, setLoading] = useState(true);//로딩여부 로딩중:true, 로딩끝:false
      const [hasMore, setHasMore] = useState(true); // 다음 페이지가 있는지 여부
      const target = useRef<HTMLDivElement | null>(null);
      const size = 10; // 한 페이지당 표시할 아이템 수
      const token = localStorage.getItem('token');
      const settings = {
        dots: true,
        infinite: false,
        arrow: true,
        speed: 500,
        slidesToShow: 1,
        slidesToScroll: 1,
        nextArrow: (
          <NextTo>
            <Arrow src={NextArrow} />
          </NextTo>
        ),
        prevArrow: (
            <Arrow src={PrevArrow} />
    

    ), };

      const postComment = () => {
        //게시하면 새롭게 댓글불러오기
      }
      // feeds 배열을 최신순으로 정렬
      const sortedFeeds: FeedType[] = (feeds.length > 0) ? feeds.slice().sort((a, b) => {
        // 'createdAt' 속성을 기준으로 비교
        return new Date(b.feedCreatedAt).getTime() - new Date(a.feedCreatedAt).getTime();
      }) : [];
      const fetchFeedsData = async () => {
        setLoading(true);
        try {
          const response = await axios.get(`${API_BASE_URL}/app/feeds`, {
            params: {
              'pageIndex': page,
              'size': size
            },
            headers: {
              'x-access-token': `${token}`,
            },
          })
          console.log('page: ',page,'조회결과', response.data.result);
          const data = response.data.result;
          console.log('prev: ', feeds, 'data: ',data) ;
          setfeeds(prev => [...prev, ...data]);
          // 각 피드에 대한 댓글 데이터 가져오기
          data.forEach((feed: FeedType) => {
            fetchAndSetComments(feed.feedId);
          });
          if (data.length < size) {
            setHasMore(false);
          }
          setLoading(false);
        } catch (error) {
          console.log('페이지 피드 조회 실패: ', error);
          setLoading(false);
          throw error;
        }
      };
      const fetchAndSetComments = async (feedId: number) => {
        try {
          const response = await axios.get(`${API_BASE_URL}/app/feeds/${feedId}/comments`, {
            params: {
              'pageIndex': 0,
              'size': size
            },
            headers: {
              'x-access-token': `${token}`,
            },
          })
          const commentsData = response.data.result;
          console.log('CommentsData', commentsData);
          //해당피드를 찾아서 comments설정
          setfeeds((prevfeeds) => {
            const updatedfeeds = prevfeeds.map((feed) => {
              if (feed.feedId === feedId) {
                return {
                  ...feed,
                  comments: commentsData
                };
              }
              return feed;
            });
            return updatedfeeds;
          });
        } catch (error) {
          console.log('페이지 댓글설정 실패: ', error);
        }
      };
      // 페이지 로딩 시 댓글 데이터를 초기 로드
      useEffect(() => {
        console.log('DashboardModified', DashboardModified);
        if (DashboardModified || Posted) {//게시글 수정 및 삭제 또는 feed게시
          console.log('dashboard가 수정 및 삭제되거나 게시글이 새롭게 업로드외서 실행되는 fetchFeedData');
          setLoading(true);
          fetchFeedsData();
        }
        if (DashboardModified) {
          setDashboardModified(false);
        } else if (Posted) {
          setPosted(false);
        }
      }, [DashboardModified, Posted]);
      useEffect(() => {
          console.log('페이지가 바뀌어서실행횓는 fetchFeedData');
          setLoading(true);
          fetchFeedsData();
      },[page]);
      useEffect(() => {
        if (target.current && !loading) {
          console.log('페이지 + 1');
          //로딩완료되었을때만 실행(로딩중=target을 찾는중)
          const observer = new IntersectionObserver(
            entries => {
              if (entries[0].isIntersecting) {
                setPage(prev => prev + 1)
              }
            },
            { threshold: 1 }
          );
          observer.observe(target.current);
        }
      }, [loading]);
      const [showMore, setShowMore] = useState(false); //더보기여부
      const [heart, setHeart] = useState(false);
      const [hearCounts, setHeartCounts] = useState(251);
      const handleCloseModal = (newState: boolean) => {
        setSelectedFeed(null);
        setDashboardIsOpen(newState);
      }
      return (
        <>
          {sortedFeeds && sortedFeeds.map(function (feed) {
            const sortedComments = feed.comments ? (feed.comments.slice().sort((a, b) => {
              return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
            })) : []
            const fullText = feed.feedLoginId + ' ' + feed.feedText;
            const getDayMinuteCounter = (date?: Date): number | string => {
              if (!date) {
                return '';
              }
              const today = moment();
              const commentDate = moment(date);
              const dayDiff = today.diff(commentDate, 'days');
              const hourDiff = today.diff(commentDate, 'hours');
              const minutesDiff = today.diff(commentDate, 'minutes');
              if (dayDiff === 0 && hourDiff === 0) { // 작성한지 1시간도 안지났을때
                const minutes = Math.abs(minutesDiff);// 절대값 사용
                return minutes + '분 전';		 // '분' 로 표시
              }
              else if (dayDiff === 0 && hourDiff <= 24) { // 작성한지 1시간은 넘었지만 하루는 안지났을때, 
                const hour = Math.abs(hourDiff);
                return hour + '시간 전';		 // '시간'으로 표시
              }
              else if (-dayDiff >= 30) {
                const formattedDate = moment(date).format('YYYY년 MM월 DD일');
                return formattedDate;
              }
              else {
                return Math.abs(dayDiff) + '일 전';		 // '일'로 표시
              }
            };
            const handleHeart = () => {
              if (heart) {
                setHeart(false);
                setHeartCounts(hearCounts - 1);
              } else {
                setHeart(true);
                setHeartCounts(hearCounts + 1)
              }
            }
            const handleOpenModal = () => {
              setSelectedFeed(feed);
              setDashboardIsOpen(true);
            };
            return (
              <PostContainer key={feed.feedId}>
                <PostImage>
                  <PostUserInfo>
                    <FeedLoginProfile></FeedLoginProfile>
                    <PostUserName>{feed.feedLoginId}</PostUserName>
                  </PostUserInfo>
                  <StyledSlider {...settings}>
                    <SliderImg src={feed.contentsList[0].contentsUrl} alt={`postImage`} />
                  </StyledSlider>
                </PostImage>
                <div className="PostActions">
                  <PostIcons>
                    <Likes>
                      <HeartBtn onClick={handleHeart}>
                        <HeartIcon width="24" height="24" heart={heart}></HeartIcon>
                      </HeartBtn>
                      <Comment width="24" height="24"></Comment>
                    </Likes>
                    <Bookmark stroke="black" width="24" height="24"></Bookmark>
                  </PostIcons>
                  <Reactions>
                    <LikesCount>좋아요 {hearCounts}개</LikesCount>
                    <div className="PostText">
                      {
                        showMore ?
                          <>
                            <FeedUserId>{feed.feedLoginId}
                            </FeedUserId><FeedText>{feed.feedText}</FeedText>
                          </>
                          : <>
                            <FeedUserId>{feed.feedLoginId}</FeedUserId>
                            <FeedText>{feed.feedText.slice(0, (100 - feed.feedLoginId.length))}</FeedText>
                          </>
                      }
                      {/*펼쳤을때는 더보기가 안보이게 -> !showmore*/}
                      {!showMore && fullText.length > 100 && <ViewMore onClick={() => { setShowMore(true) }} className="ViewMore">...더보기</ViewMore>}
                    </div>
                    <PostComments>
                      {
                        sortedComments.slice(0, 2).map((comment) => (
                          <CommentBox>
                            <CommentProfile></CommentProfile>
                            <div>
                              <CommentId>{comment.loginId}</CommentId><CommentContent>{comment.commentText}</CommentContent>
                              <p>{getDayMinuteCounter(new Date(comment.createdAt))}</p>
                            </div>
                          </CommentBox>
                        ))
                      }
                      {/*펼쳤을때는 더보기가 안보이게 -> !showmore*/}
                      {feed.feedCommentCount > 2 && <CommentsMore onClick={handleOpenModal}>댓글 {feed.feedCommentCount}개 모두 보기</CommentsMore>}
                      <p style={{ fontSize: "12px", color: "#B2B2B2" }}>{getDayMinuteCounter(new Date(feed.feedCreatedAt))}</p>
                    </PostComments>
                  </Reactions>
                  <CommentWrapper>
                    <CommentingUser></CommentingUser>
                    <CommentInput onClick={handleOpenModal}>댓글 달기...</CommentInput>
                    <Posting onClick={postComment}>게시</Posting>
                    {dashboardIsOpen && (
                      <Modal isOpen={dashboardIsOpen} onRequestClose={() => { handleCloseModal(false) }}
                        contentLabel="게시물 상세 모달"
                        style={ModalStyle}
                      >
                        {selectedFeed && (
                          <Dashboard selectedFeed={selectedFeed} isOpen={dashboardIsOpen} onRequestClose={handleCloseModal}></Dashboard>
                        )}
                      </Modal>)}
                  </CommentWrapper>
                </div>
              </PostContainer>
            );
          })}
          {hasMore && <div ref={target}>loading...</div>}
        </>
      );
    }
    export default Post;
    우선 현재 페이징 무한 스크롤을(게시글 10개마다 스크롤이 되도록) 구현중입니다.
    위 코드에서 문제는 하나의 게시글을 삭제했을 때 새롭게 게시글데이터 10개를 가져오면 끝나야할것을 page를 1증가시켜 그다음 게시글데이터 10개까지 가져와 총 20개가 로드됩니다.
    
     2
    처음 페이지가 렌더링될때는 10개의 데이터만 가져와집니다. 
    
    1
    또한 가지 문제점은 게시글을 한번 삭제했을때는 해당 게시글이 삭제된 게시글목록이 잘 나타나지만,
    한번더 게시글을 삭제하면 fetchFeedsData가 2번씩 호출돼서그런지,, 같은 피드목록이 2번씩 중복되어 나타납니다..
    알고리즘을 복잡하게 짜다보니 코드가 꼬이게 된것같습니다..ㅜ
    어떤식으로 수정하면 좋을까요
    #98803

    codingapple
    키 마스터
    글없애면 그만큼 화면 높이가 줄어들어서 그럴수도요 
    화면높이 최솟값을 설정해주거나 글없애면 무한스크롤기능 잠깐 정지시키거나 그래야할듯요 
    fetchFeedsData()는 다른 useEffect로 빼봅시다 
    
2 글 보임 - 1 에서 2 까지 (총 2 중에서)
  • 답변은 로그인 후 가능합니다.

About

현재 월 700명 신규수강중입니다.

  (09:00~20:00) 빠른 상담은 카톡 플러스친구 코딩애플 (링크)
  admin@codingapple.com
  이용약관, 개인정보처리방침
ⓒ Codingapple, 강의 예제, 영상 복제 금지
top

© Codingapple, All rights reserved. 슈퍼로켓 에듀케이션 / 서울특별시 강동구 고덕로 19길 30 / 사업자등록번호 : 212-26-14752 온라인 교육학원업 / 통신판매업신고번호 : 제 2017-서울강동-0002 호 / 개인정보관리자 : 박종흠