devcisive / solumon-frontend

0 stars 3 forks source link

게시글 검색 결과를 원하는 순서로 정렬할 때 postCard 순서 업데이트가 하나씩 밀리는 문제 #76

Closed chaeeunj closed 7 months ago

chaeeunj commented 8 months ago

SearchResult.jsx

현재 검색 페이지에서 키워드를 입력한 후 해당 키워드에 대한 검색 결과 페이지로 이동하면 검색 결과를 원하는 순서로 정렬(최신순, 채팅 참여 순, 투표 참여 순, 마감 임박 순)할 수 있게 구현을 했습니다.

하지만 검색 결과에 해당하는 게시글들이 원하는 순서로 바로 정렬되지 않고 한 차례씩 뒤로 밀리는 문제가 생겼습니다. 게시글 정렬 기능은 최신순 -> 채팅 참여 순 -> 투표 참여 순 -> 마감 임박 순 으로 테스트해보았는데 아래의 사진들과 같이 image 채팅 참여 순 정렬을 클릭하면 최신순으로 게시글이 정렬되고


image 투표 참여 순 정렬을 클릭하면 채팅 참여 순으로 게시글이 정렬되며


image 마감 임박 순 정렬을 클릭하면 투표 참여 순으로 게시글이 정렬되는 문제를 확인할 수 있습니다.



  const handleSortChange = async (sortValue) => {
    if (sortValue === '최신순') {
      filterSearchData('created_at', 'desc');
    } else if (sortValue === '채팅 참여 순') {
      filterSearchData('total_comment_count', 'desc');
    } else if (sortValue === '투표 참여 순') {
      filterSearchData('total_vote_count', 'desc');
    } else {
      filterSearchData('created_at');
    }
  };

정렬 탭(SortSelect)을 클릭하면 handleSortChange 함수가 실행되며 해당하는 순서대로 게시글을 정렬해주는 함수 filterSearchData를 호출하게 되고

const fetchOrderedData = async (orderByField, order) => {
    const querySnapshot = await getDocs(
      query(collection(db, 'posts-write'), orderBy(orderByField, order)),
    );

    const dataList = [];
    querySnapshot.forEach((doc) => {
      dataList.push({
        postId: doc.id,
        ...doc.data(),
      });
    });

    setPostData(dataList);
  };

 const filterSearchData = async (orderByField, order) => {
    await fetchOrderedData(orderByField, order);

    if (postData.length > 0) {
      const filteredData = postData.filter((item) =>
        item.title.includes(keyword),
      );

      setSearchData(filteredData);
    }
  };

filterSearchData 함수는 fetchOrderedData 함수를 통해 firestore에 저장된 게시글 데이터를 불러온 후 검색어에 일치하는 게시글들을 필터링하여 postCard 컴포넌트에 게시글 데이터를 전달해주는 방식으로 코드를 작성했습니다.



문제의 원인

리액트의 비동기적 특징 으로 인해 filterSearchData 함수가 순차적으로 진행되는 것을 보장할 수 없기 때문에 정렬 상태가 즉시 업그레이드 되지 않는 문제가 발생한 것이라고 판단했습니다. 현재 filterSearchData 함수에서는 fetchOrderedData 호출 후에 조건문을 사용하여 postData가 존재할 때 게시글 필터링을 진행하게 했지만 이는 fetchOrderedData 함수가 먼저 실행되었는지 확실하게 보장할 수 없기 때문에 코드를 아래와 같이 수정했습니다.




해결 방법

  const fetchOrderedData = async (orderByField, order) => {
    const querySnapshot = await getDocs(
      query(collection(db, 'posts-write'), orderBy(orderByField, order)),
    );

    const dataList = [];
    querySnapshot.forEach((doc) => {
      dataList.push({
        postId: doc.id,
        ...doc.data(),
      });
    });

    return dataList;
  };

const filterSearchData = async (orderByField, order) => {
    const data = await fetchOrderedData(orderByField, order);

    if (data.length > 0) {
      const filteredData = data.filter((item) => item.title.includes(keyword));

      setSearchData(filteredData);
    }
  };

그냥 fetchOrderedData 함수를 호출하는 것이 아니라 fetchOrderedData 함수의 실행 결과를 data 변수에 저장하고, data 객체가 존재할 때 게시글 필터링을 진행하게 하자 코드가 정상적으로 작동하는 것을 확인했습니다. 또한 fetchOrderedData 함수의 실행 결과를 변수에 저장해야 하기 때문에 fetchOrderedData 함수에서 게시글들이 저장된 dataList 값을 setPostData(dataList); 로 저장하지 않고return dataList 으로 그냥 리턴하도록 수정했습니다.